बैश 5.0 में हल किया गया
पृष्ठभूमि
पृष्ठभूमि के लिए (और समझ (और इस सवाल को आकर्षित करने से बचने की कोशिश कर रहा है) को आकर्षित करने के लिए) मैं उस पथ को समझाऊंगा जो मुझे इस मुद्दे पर मिला (ठीक है, सबसे अच्छा मैं दो महीने बाद याद कर सकता हूं)।
मान लें कि आप यूनिकोड वर्णों की सूची के लिए कुछ शेल परीक्षण कर रहे हैं:
printf "$(printf '\\U%x ' {33..200})"
और 1 मिलियन से अधिक यूनिकोड वर्ण होने के कारण, उनमें से 20.000 का परीक्षण करना उतना प्रतीत नहीं होता है।
यह भी मान लें कि आप पात्रों को स्थितीय तर्क के रूप में सेट करते हैं:
set -- $(printf "$(printf '\\U%x ' {33..20000})")
प्रत्येक फ़ंक्शन को अलग-अलग तरीकों से संसाधित करने के लिए पात्रों को पास करने के इरादे से। तो फ़ंक्शंस में फॉर्म test1 "$@"
या समान होना चाहिए । अब मुझे एहसास हुआ कि यह कितना बुरा विचार है।
अब, मान लें कि प्रत्येक समाधान के लिए समय (n = 1000) की आवश्यकता है, जो कि बेहतर है, ऐसी परिस्थितियों में आप इस तरह की संरचना के साथ समाप्त हो जाएंगे:
#!/bin/bash --
TIMEFORMAT='real: %R' # '%R %U %S'
set -- $(printf "$(printf '\\U%x ' {33..20000})")
n=1000
test1(){ echo "$1"; } >/dev/null
test2(){ echo "$#"; } >/dev/null
test3(){ :; }
main1(){ time for i in $(seq $n); do test1 "$@"; done
time for i in $(seq $n); do test2 "$@"; done
time for i in $(seq $n); do test3 "$@"; done
}
main1 "$@"
test#
यहां प्रस्तुत किए जाने वाले कार्यों को बहुत सरल बनाया गया है।
मूल रूप से उत्तरोत्तर बड़े पैमाने पर देरी कहां हुई, यह जानने के लिए मूल रूप से छंटनी की गई।
ऊपर की स्क्रिप्ट काम करती है, आप इसे चला सकते हैं और कुछ सेकंड बर्बाद कर सकते हैं।
यह पता लगाने के लिए सरलीकरण की प्रक्रिया में कि देरी कहाँ हुई (और प्रत्येक परीक्षण कार्य को लगभग कुछ भी नहीं होने के कारण, कई परीक्षणों के बाद चरम पर है) मैंने यह जानने के लिए प्रत्येक परीक्षण फ़ंक्शन के तर्कों को हटाने का निर्णय लिया कि समय कितना सुधरा है, केवल 6 का कारक, ज्यादा नहीं।
अपने आप को आज़माने के लिए, सभी "$@"
फंक्शन को हटा दें main1
(या कॉपी बनाएं) और तुलना करने के लिए फिर से (या दोनों main1
और कॉपी main2
( main2 "$@"
) के साथ ) टेस्ट करें। यह मूल संरचना नीचे मूल पोस्ट (ओपी) में है।
लेकिन मैंने सोचा: शेल को "कुछ नहीं" करने के लिए इतना समय क्यों लग रहा है? हाँ, केवल "कुछ सेकंड", लेकिन फिर भी, क्यों?।
इससे मुझे अन्य गोले में परीक्षण करने के लिए पता चला कि केवल बैश में यह मुद्दा था।
कोशिश करो ksh ./script
(ऊपर के रूप में एक ही स्क्रिप्ट)।
यह इस विवरण को जन्म देता है: test#
किसी भी तर्क के बिना एक फ़ंक्शन ( ) को कॉल करना अभिभावक में तर्कों द्वारा देरी हो जाती है ( main#
)। यह वह वर्णन है जो निम्न था और नीचे मूल पोस्ट (ओपी) था।
मूल पोस्ट।
एक फ़ंक्शन को कॉल करना (बैश 4.4.12 (1) -release) में कुछ भी नहीं करने f1(){ :; }
की तुलना में एक हजार गुना धीमा है, :
लेकिन केवल अगर पैरेंट कॉलिंग फ़ंक्शन में परिभाषित तर्क हैं , तो क्यों?
#!/bin/bash
TIMEFORMAT='real: %R'
f1 () { :; }
f2 () {
echo " args = $#";
printf '1 function no args yes '; time for ((i=1;i<$n;i++)); do : ; done
printf '2 function yes args yes '; time for ((i=1;i<$n;i++)); do f1 ; done
set --
printf '3 function yes args no '; time for ((i=1;i<$n;i++)); do f1 ; done
echo
}
main1() { set -- $(seq $m)
f2 ""
f2 "$@"
}
n=1000; m=20000; main1
के परिणाम test1
:
args = 1
1 function no args yes real: 0.013
2 function yes args yes real: 0.024
3 function yes args no real: 0.020
args = 20000
1 function no args yes real: 0.010
2 function yes args yes real: 20.326
3 function yes args no real: 0.019
फ़ंक्शन में कोई तर्क या इनपुट या आउटपुट का उपयोग नहीं किया जाता है f1
, एक हजार (1000) के कारक का विलंब अप्रत्याशित है। 1
कई गोले में परीक्षण का विस्तार, परिणाम सुसंगत हैं, अधिकांश गोले को कोई परेशानी नहीं होती है और न ही विलंब का सामना करना पड़ता है (उसी n और m का उपयोग किया जाता है):
test2(){
for sh in dash mksh ksh zsh bash b50sh
do
echo "$sh" >&2
# \time -f '\t%E' seq "$m" >/dev/null
# \time -f '\t%E' "$sh" -c 'set -- $(seq '"$m"'); for i do :; done'
\time -f '\t%E' "$sh" -c 'f(){ :;}; while [ "$((i+=1))" -lt '"$n"' ]; do : ; done;' $(seq $m)
\time -f '\t%E' "$sh" -c 'f(){ :;}; while [ "$((i+=1))" -lt '"$n"' ]; do f ; done;' $(seq $m)
done
}
test2
परिणाम:
dash
0:00.01
0:00.01
mksh
0:00.01
0:00.02
ksh
0:00.01
0:00.02
zsh
0:00.02
0:00.04
bash
0:10.71
0:30.03
b55sh # --without-bash-malloc
0:00.04
0:17.11
b56sh # RELSTATUS=release
0:00.03
0:15.47
b50sh # Debug enabled (RELSTATUS=alpha)
0:04.62
xxxxxxx More than a day ......
पुष्टि करने के लिए अन्य दो परीक्षणों को रद्द करें कि न तो seq
या तर्क सूची को संसाधित करना देरी के लिए स्रोत है।
1 यहज्ञात है कि तर्कों द्वारा परिणाम पारित करने से निष्पादन समय बढ़ जाएगा। धन्यवाद@ एसएलएम