dash 또는 다른 쉘이 bash보다 "빠르나요"?

dash 또는 다른 쉘이 bash보다 "빠르나요"?

나는 항상 bash 대신 dash를 사용하는 유일한 이점은 dash가 더 작기 때문에 많은 dash 인스턴스가 시작 시 더 빨리 시작된다는 것이라고 생각했습니다.

하지만 조사를 해보니 어떤 사람들은 더 빨리 실행되기를 바라면서 모든 스크립트를 dash로 마이그레이션한다는 사실을 발견했습니다. 기사에서도 이 내용을 발견했습니다.대시우분투 위키피디아에서:

기본 쉘을 전환하는 주된 이유는능률. bash는 대화형 사용에 적합한 뛰어난 모든 기능을 갖춘 쉘이며 실제로 여전히 기본 로그인 쉘입니다. 다만 규모가 꽤 크고느린 시작그리고 운영하다대시와 비교.

요즘 나는 내 시스템의 많은 작업에 bash 스크립트를 많이 사용합니다. 내 문제는 연중무휴 24시간 연속으로 실행하는 특정 스크립트가 있고 이 스크립트가 함께 내 컴퓨터를 다운시키는 약 200개의 첨자를 생성한다는 것입니다. 최대 10°C 이상 가열됩니다. 평소 사용시보다

bashism이 많이 포함된 꽤 큰 스크립트이므로 이를 POSIX나 다른 쉘로 포팅하는 데 시간이 꽤 많이 걸릴 것입니다(POSIX는 개인 용도로 그다지 중요하지 않습니다). 그러나 일부를 줄일 수 있다면 가치가 있을 것입니다. CPU 사용량입니다. 예 를 들어 sed간단한 bashism을 호출 하기 위해 외부 바이너리를 호출하는 것과 같이 고려해야 할 다른 사항이 있다는 것을 알고 있습니다 .${foo/bar}grep=~

긴 이야기 짧게bash 시작 속도가 정말 느립니다.그리고 운영하다대시와 비교하면? 더 강력한 Unix 쉘이 있습니까?효율적인배쉬보다?

답변1

쉘 순서:

아마도 쉘 성능을 벤치마킹하는 유용한 방법은 매우 작고 간단한 평가를 다수 반복하는 것입니다. 나는 단순히 루프를 반복하지 않는 것이 중요하다고 생각합니다.입력하다, 쉘이 읽어야 하기 때문입니다 <&0.

나는 이것이 테스트를 보완할 것이라고 생각했습니다@cuonglm 게시됨호출 시 셸 프로세스가 얼마나 빨리 로드되는지 보여주기보다는 호출 후 단일 셸 프로세스의 성능을 보여주기 때문입니다. 이런 식으로 우리는 우리 사이의 동전의 양면을 덮습니다.

쉽게 시연할 수 있는 기능은 다음과 같습니다.

sh_bench() (                                               #don't copy+paste comments
    o=-c sh=$(command -v "$1") ; shift                     #get shell $PATH; toss $1
    [ -z "${sh##*busybox}" ] && o='ash -c'                 #cause its weird
    set -- "$sh" $o "'$(cat <&3)'" -- "$@"                 #$@ = invoke $shell
    time env - "$sh" $o "while echo; do echo; done|$*"     #time (env - sh|sh) AC/DC
) 3<<-\SCRIPT                                                                      
#Everything from here down is run by the different shells    
    i="${2:-1}" l="${1:-100}" d="${3:-                     
}"; set -- "\$((n=\$n\${n:++\$i}))\$d"                     #prep loop; prep eval
    set -- $1$1$1$1$1$1$1$1$1$1                            #yup
while read m                                           #iterate on input
    do  [ $(($i*50+${n:=-$i})) -gt "$(($l-$i))" ] ||       #eval ok?
            eval echo -n \""$1$1$1$1$1"\"                  #yay!
        [ $((n=$i+$n)) -gt "$(($l-$i))" ] &&               #end game?
            echo "$n" && exit                              #and EXIT
            echo -n "$n$d"                                     #damn - maybe next time
    done                                                   #done 
    #END
    SCRIPT                                                     #end heredoc

각 줄바꿈을 읽을 때마다 변수를 한 번씩 증가시키거나 (가능한 경우) 약간의 최적화로 각 줄바꿈을 읽을 때마다 변수를 50배씩 증가시킵니다. 변수가 증가할 때마다 에 인쇄됩니다 stdout. 이는 일종의 seq십자가 처럼 동작합니다 nl.

이것이 수행하는 작업을 매우 명확하게 하기 위해 위의 함수 set -x;앞에 삽입한 후 일부 잘린 출력이 있습니다.time

time env - /usr/bin/busybox ash -c '
     while echo; do echo; done |
     /usr/bin/busybox ash -c '"'$(
         cat <&3
     )'"' -- 20 5 busybox'

따라서 각 쉘은 먼저 다음과 같이 호출됩니다.

 env - $shell -c "while echo; do echo; done |..."

3<<\SCRIPT...읽는 동안 반복되어야 하는 입력을 생성합니다 cat. 반면에 |pipe다음과 같이 다시 자신을 호출합니다.

"...| $shell -c '$(cat <<\SCRIPT)' -- $args"

그래서 초기 전화통화 외에env ( cat실제로는 이전 줄에서 호출되었기 때문입니다); 호출된 시점부터 종료되는 시점까지 다른 프로세스는 호출되지 않습니다. 적어도 그것이 사실이기를 바랍니다.

숫자 앞에...

이식성에 관해 몇 가지 메모를 해야 합니다.

  • posh싫어 $((n=n+1))하고 고집해$((n=$n+1))

  • mkshprintf대부분의 경우 내장된 기능이 없습니다. 초기 테스트에서는 지연이 많이 발생하여 /usr/bin/printf실행될 때마다 호출되었습니다. 그래서 위와 같은 상황이 발생합니다 echo -n.

  • 아마 내 기억으로는 더 많을지도...

어쨌든 숫자를 보면 다음과 같습니다.

for sh in dash busybox posh ksh mksh zsh bash
do  sh_bench $sh 20 5 $sh 2>/dev/null
    sh_bench $sh 500000 | wc -l
echo ; done

이렇게 하면 모든 작업을 완료할 수 있습니다...

0dash5dash10dash15dash20

real    0m0.909s
user    0m0.897s
sys     0m0.070s
500001

0busybox5busybox10busybox15busybox20

real    0m1.809s
user    0m1.787s
sys     0m0.107s
500001

0posh5posh10posh15posh20

real    0m2.010s
user    0m2.060s
sys     0m0.067s
500001

0ksh5ksh10ksh15ksh20

real    0m2.019s
user    0m1.970s
sys     0m0.047s
500001

0mksh5mksh10mksh15mksh20

real    0m2.287s
user    0m2.340s
sys     0m0.073s
500001

0zsh5zsh10zsh15zsh20

real    0m2.648s
user    0m2.223s
sys     0m0.423s
500001

0bash5bash10bash15bash20

real    0m3.966s
user    0m3.907s
sys     0m0.213s
500001

    

아무 = 어쩌면?

그래도 이것은 상당히 임의적인 테스트이지만 입력 읽기, 산술 평가 및 변수 확장을 테스트합니다. 포괄적이지는 않지만 아마도 거기에 가깝습니다.

편집자: Teresa e Junior: @mikeserv와 저는 다른 많은 테스트를 수행했습니다(참조우리 채팅세부사항) 결과를 다음과 같이 요약할 수 있음을 확인했습니다.

  • 속도가 필요하다면 꼭 선택하세요스프린트, 이는 다른 쉘보다 훨씬 빠릅니다.세게 때리다.
  • 하지만바쁜 상자껍질이 아마 더 좋을 것 같아요스프린트, 일반적으로 사용되는 GNU 유틸리티만큼 많은 기능은 없지만 그만큼 많은 작업을 수행할 수 있는 , , grep등과 같은 자체 사용자 공간 유틸리티가 많기 때문에 일부 테스트에서는 더 빠를 수 있습니다. .sedsort
  • 속도가 당신의 전부가 아니라면케시(또는크쉬 93)은 속도와 기능성 사이의 최선의 절충안으로 간주될 수 있습니다. 작은 것에 비해 속도가 빠르다므케시, 이는 것보다 낫습니다.세게 때리다이며 다음과 같은 몇 가지 고유한 기능도 있습니다.부동 소수점 연산.
  • 하지만세게 때리다단순성, 안정성 및 기능성으로 잘 알려져 있지만 대부분의 테스트에서 모든 쉘 중에서 가장 느렸으며 속도도 매우 다양했습니다.

답변2

벤치마크 테스트를 해보자.

그리고 bash:

$ strace -cf bash -c 'for i in $(seq 1 1000); do bash -c ":"; done'

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 99.12    0.376044         188      2004      1002 wait4
  0.74    0.002805           3      1002           clone
  0.03    0.000130           0      4037           read
  0.03    0.000119           0     15026           rt_sigprocmask
  0.03    0.000096           0     15040      6017 stat
  0.01    0.000055           0      8011           open
  0.01    0.000024           0      5013           getegid
  0.01    0.000021           0     16027           rt_sigaction
  0.00    0.000017           0      9020      5008 access
  0.00    0.000014           0      1001      1001 getpeername
  0.00    0.000013           0      1001           getpgrp
  0.00    0.000012           0      5013           geteuid
  0.00    0.000011           0     15025           mmap
  0.00    0.000011           0      1002           rt_sigreturn
  0.00    0.000000           0         1           write
  0.00    0.000000           0      8017           close
  0.00    0.000000           0      7011           fstat
  0.00    0.000000           0      8012           mprotect
  0.00    0.000000           0      2004           munmap
  0.00    0.000000           0     18049           brk
  0.00    0.000000           0         1           pipe
  0.00    0.000000           0         1           dup2
  0.00    0.000000           0      1001           getpid
  0.00    0.000000           0      1002           execve
  0.00    0.000000           0      1001           uname
  0.00    0.000000           0      1001           getrlimit
  0.00    0.000000           0      5013           getuid
  0.00    0.000000           0      5013           getgid
  0.00    0.000000           0      1001           getppid
  0.00    0.000000           0      1002           arch_prctl
  0.00    0.000000           0      1001           time
------ ----------- ----------- --------- --------- ----------------
100.00    0.379372                158353     13028 total

그리고 dash:

$ strace -cf bash -c 'for i in $(seq 1 1000); do dash -c ":"; done'
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 73.88    0.008543           4      2004      1002 wait4
 25.35    0.002932           3      1002           clone
  0.62    0.000072           0      9026           rt_sigprocmask
  0.10    0.000011           0      1002           rt_sigreturn
  0.05    0.000006           0     15027           rt_sigaction
  0.00    0.000000           0      1037           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0      2011           open
  0.00    0.000000           0      2017           close
  0.00    0.000000           0      2040        17 stat
  0.00    0.000000           0      2011           fstat
  0.00    0.000000           0      8025           mmap
  0.00    0.000000           0      3012           mprotect
  0.00    0.000000           0      1004           munmap
  0.00    0.000000           0      3049           brk
  0.00    0.000000           0      3020      3008 access
  0.00    0.000000           0         1           pipe
  0.00    0.000000           0         1           dup2
  0.00    0.000000           0      1001           getpid
  0.00    0.000000           0         1         1 getpeername
  0.00    0.000000           0      1002           execve
  0.00    0.000000           0         1           uname
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0        13           getuid
  0.00    0.000000           0        13           getgid
  0.00    0.000000           0      1013           geteuid
  0.00    0.000000           0        13           getegid
  0.00    0.000000           0      1001           getppid
  0.00    0.000000           0         1           getpgrp
  0.00    0.000000           0      1002           arch_prctl
  0.00    0.000000           0         1           time
------ ----------- ----------- --------- --------- ----------------
100.00    0.011564                 60353      4028 total

반복당 하나의 셸만 시작되며 무작동 연산자로는 아무 작업도 수행하지 않습니다.콜론을 누른 다음 종료합니다.

결과는 시작할 때보다 훨씬 빠르다는 것을 보여줍니다 dash. 다음보다 더 작고 더 적은 수의 공유 라이브러리에 의존합니다.bashdashbash

$ du -s /bin/bash 
956 /bin/bash

$ du -s /bin/dash 
108 /bin/dash

$ ldd /bin/bash
    linux-vdso.so.1 =>  (0x00007fffc7947000)
    libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f5a8110d000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5a80f09000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a80b7d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f5a81352000)

$ ldd /bin/dash
    linux-vdso.so.1 =>  (0x00007fff56e5a000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb24844c000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fb2487f3000)

부팅 시간과 작동 방식에 관한 것입니다. 또 다른 벤치마크를 해보겠습니다.

$ time dash -c 'for i in $(seq 1 1000000);do [ 1 = 1 ];done'

real    0m2.684s
user    0m2.728s
sys     0m0.100s

$ time bash -c 'for i in $(seq 1 1000000);do [ 1 = 1 ];done'

real    0m6.996s
user    0m6.820s
sys     0m0.376s

간단한 테스트 후에도 1 = 1여전히 dash훨씬 빠릅니다 bash.

답변3

다음은 인증된 UNIX(Mac OS X 10.10.3)의 다양한 셸에 대한 몇 가지 시작 순서입니다. 테스트 중인 쉘이 루프를 제어하는 ​​쉘이 아니도록 tcsh를 사용하여 루프를 제어하도록 테스트를 다시 작성했습니다. 각 셸에 대해 루프는 타이밍 전에 5번 실행되어 셸 실행 파일과 스크립트가 캐시에 있는지 확인합니다.

보시다시피 확실한 승자는 없지만 확실한 패자는 있습니다. 어쨌든 bash 4는 bash 3보다 훨씬 느립니다. Dash는 잘 작동하지만 ksh93이 이제 오픈 소스라는 점을 고려하면 이를 모든 목적으로 사용하지 않을 실질적인 이유가 없습니다(라이센스 세부 사항을 잘못 이해했다면 사과드립니다). ksh93은 빠르고 안정적이며 UNIX 세계에서 사실상의 표준입니다( if GNU/Linux 영역에는 없음) POSIX 쉘 기능의 상위 세트를 제공합니다(내가 아는 한 POSIX 쉘은 ksh88을 기반으로 합니다). 대화형 쉘은 bash와 동일하지만 tcsh보다 뒤떨어집니다. 패자는 물론 zsh입니다.

/bin/bash is v3.2.57(1)
/usr/local/bin/bash is v4.3.33(1)
dash is v0.5.8
ksh is v93u+
mksh is vR50f
pdksh is v5.2.14
/opt/heirloom/5bin/sh is from SysV
yash is v2.37
zsh is v5.0.5

% cat driver.csh 
#!/bin/tcsh

foreach s ( $* )
    echo
    echo "$s"
    foreach i ( `seq 1 5` )
        ./simple_loop.csh "$s"
    end
    /usr/bin/time -p ./simple_loop.csh "$s"
end

% cat simple_loop.csh 
#!/bin/tcsh

set shell = `which ${1}`
foreach i ( `seq 1 1000` )
    ${shell} -c ":"
end

% ./driver.csh /bin/bash /usr/local/bin/bash dash ksh mksh pdksh /opt/heirloom/5bin/sh yash zsh 
/bin/bash
real         4.21
user         1.44
sys          1.94

/usr/local/bin/bash
real         5.45
user         1.44
sys          1.98

dash
real         3.28
user         0.85
sys          1.11

ksh
real         3.48
user         1.35
sys          1.68

mksh
real         3.38
user         0.94
sys          1.14

pdksh
real         3.56
user         0.96
sys          1.17

/opt/heirloom/5bin/sh
real         3.46
user         0.92
sys          1.11

yash
real         3.97
user         1.08
sys          1.44

zsh
real        10.88
user         3.02
sys          5.80

답변4

여기에 있는 많은 답변에는 불공정한 테스트 사례가 너무 많습니다. 두 개의 쉘을 테스트하는 경우 각 쉘에 대해 올바른 구문을 사용하십시오. Bash에서는 이중 브래킷이 단일 브래킷보다 빠르고 안정적이므로 속도 차이가 훨씬 작습니다. 최적화된 bashism을 사용하는 것도 가능하며, 그러면 이러한 속도 차이도 작아집니다. 내 시스템에서 bash는 끔찍하게 실행되고 bashism을 많이 사용합니다. 그리고 대시의 posix 등가물은 여기에서 더 느립니다. dash는 항상 bash보다 몇 배 빠르기 때문에 이것은 잘못된 것입니다. 실제로 대시가 항상 가장 빠른 두 가지의 posix 명령줄을 비교하는 것은 상당히 불공평합니다. 제 생각에는 posix는 심각하게 구식입니다. 그리고 호환성 측면에서 지금은 관련 시스템을 찾기가 정말 어렵고, bash 쉘을 사용하지도 않습니다.

좋은 비교는 각 셸에서 가능한 최상의 명령줄을 사용하여 특정 작업을 수행하는 것입니다. 완전히 동일한 명령줄일 뿐만 아니라 하나의 셸만 있으면 이점이 있습니다. 이러한 비교는 신뢰할 수 없으며 경쟁업체의 실제 성과를 보여주지 못합니다. 일상 업무에서 많은 사용 사례에서 어느 쉘이 더 빠른지 확인합니다.

예를 들어 a문자열의 모든 문자를 b문자로 바꾸려면 bash에서는 작성할 수 있지만 "${varname//a/b}"대시에서는 다음과 같은 외부 도구를 호출해야 합니다 "$(echo "$varname" | sed 's/a/b/g')". 수백 번 반복해야 한다면 bashism을 사용하면 속도가 2배 향상될 수 있습니다.

관련 정보