bash 5.0에서 해결되었습니다.
배경
배경 (그리고 이해 (그리고이 질문에 대한 다운 보트를 피하려고 노력하는 것)을 피하려고 노력함) 나는이 문제에 도달 한 경로를 설명 할 것입니다 (두 달 후에 기억할 수있는 최선).
유니 코드 문자 목록에 대해 일부 쉘 테스트를 수행한다고 가정하십시오.
printf "$(printf '\\U%x ' {33..200})"
그리고 100 만 개가 넘는 유니 코드 문자가 있으며 그 중 20.000 개를 테스트하는 것은 그리 많지 않은 것 같습니다.
또한 문자를 위치 인수로 설정했다고 가정하십시오.
set -- $(printf "$(printf '\\U%x ' {33..20000})")
문자를 각 함수에 전달하여 다른 방식으로 처리 할 수 있습니다. 따라서 함수의 형식은 test1 "$@"
비슷 해야합니다 . 이제 나는 이것이 bash에 얼마나 나쁜 생각인지 알고 있습니다.
이제 각 솔루션에 시간이 필요하다고 가정하고 (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 "$@"
)) 비교를. 아래는 원래 게시물 (OP)에서 기본 구조입니다.
그러나 나는 궁금해했다 : 왜 껍질이 "아무것도하지 않는"시간이 오래 걸립니까? 예, "몇 초"이지만 여전히 왜?
이것은 다른 쉘에서 테스트하여 배쉬에만이 문제가 있음을 발견했습니다. (위와 동일한 스크립트)를
사용해보십시오 ksh ./script
.
이 설명으로 이어집니다. test#
인수없이 함수 ( )를 호출 하면 부모 ( main#
) 의 인수에 의해 지연됩니다 . 이것은 다음의 설명이며 아래의 원본 게시물 (OP)입니다.
원본 게시물.
아무것도하지 않는 (배쉬 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
function에 사용 된 인수 나 입력 또는 출력이 없으며 f1
1,000 (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
인수 목록을 처리하거나 처리하는 것이 지연의 원인이 아닌지 확인하려면 다른 두 테스트의 주석 처리를 제거하십시오 .