बैश - पुनरावृत्ति में उप-सीमाएं

Sep 22 2020

मैंने अपने प्रोडक्शन सर्वर पर बैश में पुनरावृत्ति का परीक्षण करने का निर्णय लिया।

इस कोड को किसी प्रोडक्शन मशीन पर न चलाएं!

#!/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

जवाब

1 CharlesDuffy Sep 22 2020 at 11:51

रोकथाम के तरीकों के लिए, हमारी बहन साइट यूनिक्स और लिनक्स स्टैक एक्सचेंज देखें । उनके पास मौजूद सामयिक प्रश्नों में से एक फोर्क बम को सुरक्षित रूप से बाहर निकालना है ।

अपने मूल एल्गोरिथ्म के कार्यान्वयन के रूप में जो किसी भी उपधारा को बिल्कुल भी कांटा नहीं करता है, और इस तरह संभवतः एक फोर्क बम में बदल भी नहीं सकता है जब भी बड़ी संख्या में मनमाने ढंग से पारित किया गया हो:

#!/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-compliant funcname() {का उपयोग करने से ksh पृष्ठभूमि से आने वाले लोगों के लिए कम आश्चर्य होता है , और अन्य POSIX गोले के साथ आपके कोड की संगतता में सुधार होता है; देखhttps://wiki.bash-hackers.org/scripting/obsolete (ध्यान दें कि फ़ंक्शन घोषणा सिंटैक्स एक से अधिक स्थानों पर उल्लिखित है)।