बैश - पुनरावृत्ति में उप-सीमाएं
मैंने अपने प्रोडक्शन सर्वर पर बैश में पुनरावृत्ति का परीक्षण करने का निर्णय लिया।
इस कोड को किसी प्रोडक्शन मशीन पर न चलाएं!
#!/usr/bin/bash
function fibo {
if [ $1 -le 1 ]; then echo $1
else
echo $(( $( fibo $(( $1 - 1 )) ) +
$( fibo $(( $1 - 2 )) )
))
fi
}
fibo 100
मुझे संदेह था कि यह धीमा होगा, हालांकि, उम्मीद नहीं थी कि यह समानांतर नौकरियों के दसियों को चलाएगा। मैं सोच रहा था कि क्योंकि सर्वर मल्टीकोर है, मैं इस प्रक्रिया को मार सकता हूं।
दुर्भाग्य से, सर्वर ने फ्रीज़ किया और होस्टिंग कंपनी से इसे फिर से शुरू किया।
क्या बैश में समानांतर नौकरियों को सीमित करने का एक तरीका है?
क्या टाइमर में मुख्य प्रक्रिया के पीआईडी को सेट करना और सभी बाल नौकरियों को रोकना संभव है?
बेशक, शैक्षणिक उद्देश्यों के लिए ही पूछ रहा हूँ।
संपादित करें
पूंछ प्रत्यावर्तन संस्करण एक आकर्षण की तरह काम करता है:
#!/usr/bin/bash
fibo() {
local n=$1 a=$2 b=$3
case $n in 0) echo "$a" ;;
1) echo "$b" ;; *) fibo $((n - 1)) "$b" $((a + b)) ;;
esac
}
fibo "${1:-10}" 0 1
बेंचमार्क:
time ./fibotr.sh 100
3736710778780434371
real 0m0.078s
user 0m0.000s
sys 0m0.015s
जवाब
रोकथाम के तरीकों के लिए, हमारी बहन साइट यूनिक्स और लिनक्स स्टैक एक्सचेंज देखें । उनके पास मौजूद सामयिक प्रश्नों में से एक फोर्क बम को सुरक्षित रूप से बाहर निकालना है ।
अपने मूल एल्गोरिथ्म के कार्यान्वयन के रूप में जो किसी भी उपधारा को बिल्कुल भी कांटा नहीं करता है, और इस तरह संभवतः एक फोर्क बम में बदल भी नहीं सकता है जब भी बड़ी संख्या में मनमाने ढंग से पारित किया गया हो:
#!/usr/bin/env bash
declare -g _fibo_resA _fibo_resB # be explicit that it's intentional that these
# variables aren't locals, for future readers
fibo() {
local _fibo_outvar _fibo_inVal _fibo_locResA _fibo_locResB
_fibo_outvar=$1; _fibo_inVal=$2
if [ "$_fibo_inVal" -le 1 ]; then printf -v "$_fibo_outvar" 1
else
fibo _fibo_resA "$(( _fibo_inVal - 1 ))"; _fibo_locResA=$_fibo_resA
fibo _fibo_resB "$(( _fibo_inVal - 2 ))"; _fibo_locResB=$_fibo_resB
printf -v "$_fibo_outvar" "$(( _fibo_locResA + _fibo_locResB ))"
fi
}
# note that 100 is way too big; performance breaks down between 20 and 30
# but at least it won't act like a fork bomb!
fibo result "${1:-100}" # let user pass in a value they choose echo "$result"
ऐसा क्यों लिखा जाता है?
- सबसे महत्वपूर्ण परिवर्तन को समाप्त करना था
$( ), लेकिन इसके लिए स्टडआउट पर माता-पिता को अब पासिंग आउटपुट की आवश्यकता नहीं है। इसलिए, इस उद्देश्य के लिए अप्रत्यक्ष असाइनमेंट का उपयोग करना। - नामांकित चर नामों का उपयोग (स्थानीय लोगों के लिए भी!) नाम से परिणाम वापस करते समय होने वाले संघर्षों को रोकता है: यदि उपयोगकर्ता ने किसी चर नाम के परिणाम को लिखने के लिए चुना है जो हमारे किसी भी स्थानीय से मेल खाता है, तो उनका मान स्थानीय के लिए लिखा जाएगा, न कि वैश्विक चर वे चाहते हैं कि उनका परिणाम अंदर रखा जाए।
locResAऔरlocResBउपयोग किया जाता है क्योंकि हम फोर्किंग नहीं कर रहे हैंresAऔरresBस्थानीय और नहीं बना सकते हैं ;fiboइससे पहले कि हम उन्हें वापस करने में सक्षम हों, वे परिणामों को ओवरराइट करने से रोकते हैं।funcname() {क्योंकि वाक्य रचना घोषणा प्रपत्र प्रयोग किया जाता हैfunction funcname {एक ksh-वाद है। हालांकि, ksh में, यह प्रारूप ब्लॉक के भीतर कोड का व्यवहार बदल देता है; बैश उस इरादे का सम्मान नहीं करता है। नतीजतन, POSIX-compliantfuncname() {का उपयोग करने से ksh पृष्ठभूमि से आने वाले लोगों के लिए कम आश्चर्य होता है , और अन्य POSIX गोले के साथ आपके कोड की संगतता में सुधार होता है; देखhttps://wiki.bash-hackers.org/scripting/obsolete (ध्यान दें कि फ़ंक्शन घोषणा सिंटैक्स एक से अधिक स्थानों पर उल्लिखित है)।