"에코"가 "터치"보다 훨씬 빠른 이유는 무엇입니까?

"에코"가 "터치"보다 훨씬 빠른 이유는 무엇입니까?

디렉터리에 있는 모든 xml 파일의 타임스탬프를 현재 시간으로 (재귀적으로) 업데이트하려고 합니다. 저는 Mac OSX 10.8.5를 사용하고 있습니다.

약 300,000개의 파일에 대해 다음 echo명령에는 다음이 필요합니다.10 초:

for file in `find . -name "*.xml"`; do echo >> $file; done

그러나 다음 touch명령에는 다음이 필요합니다.10 분! :

for file in `find . -name "*.xml"`; do touch $file; done

에코가 터치보다 훨씬 빠른 이유는 무엇입니까?

답변1

Bash에서는 touch외부 바이너리 echo이지만내장 케이스:

$ type echo
echo is a shell builtin
$ type touch
touch is /usr/bin/touch

touch외부 바이너리이고 파일당 한 번 호출되므로 셸 touch에서 300,000개의 인스턴스를 생성해야 하며 touch, 이는 오랜 시간이 걸립니다.

echo그러나 이는 쉘 내장 함수이므로 쉘 내장 함수의 실행에는 전혀 포크가 필요하지 않습니다. 대신 현재 셸은 모든 작업을 수행하고 외부 프로세스를 생성하지 않으므로 속도가 매우 빠릅니다.

다음은 셸 작업에 대한 두 가지 개요입니다. 를 사용하면 새로운 프로세스를 clone하는데 시간이 많이 걸리는 것을 알 수 있다 touch. /bin/echo내장 대신 셸을 사용하면 더 비슷한 결과가 표시됩니다.


터치 사용

$ strace -c -- bash -c 'for file in a{1..10000}; do touch "$file"; done'
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 56.20    0.030925           2     20000     10000 wait4
 38.12    0.020972           2     10000           clone
  4.67    0.002569           0     80006           rt_sigprocmask
  0.71    0.000388           0     20008           rt_sigaction
  0.27    0.000150           0     10000           rt_sigreturn
[...]

에코 사용

$ strace -c -- bash -c 'for file in b{1..10000}; do echo >> "$file"; done'
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 34.32    0.000685           0     50000           fcntl
 22.14    0.000442           0     10000           write
 19.59    0.000391           0     10011           open
 14.58    0.000291           0     20000           dup2
  8.37    0.000167           0     20013           close
[...]

답변2

다른 사람들이 대답했듯이 명령을 사용하는 것이 일반적으로 (필수는 아니지만) 쉘에 내장된 것보다 빠릅니다 echo. 이를 사용하면 각 파일 실행에 대해 새 프로세스를 시작하는 것과 관련된 커널 오버헤드가 제거됩니다.touchechotouch

그러나 이 효과를 얻는 가장 빠른 방법은 여전히 ​​을 사용하는 것이지만 touch각 파일에 대해 프로그램을 한 번 실행하는 대신 옵션을 사용하여 몇 번만 실행되도록 할 수 -exec있습니다 find. 이 접근 방식은 셸 루프와 관련된 오버헤드를 방지하므로 일반적으로 더 빠릅니다.

find . -name "*.xml" -exec touch {} +

가능하다면 +(대신 \;) with를 사용하여 find ... -exec각 파일을 인수로 사용하여 명령을 한 번만 실행하십시오. 매개변수 목록이 매우 긴 경우(예: 300,000개 파일의 경우) ARG_MAX한계에 가까운 매개변수 목록을 사용하여 여러 번 실행됩니다(대부분의 시스템에서).

이 접근 방식의 또 다른 장점은 원래 루프의 경우가 아닌 모든 공백 문자를 포함하는 파일 이름에 강력하다는 것입니다.

답변3

echo쉘이 내장되어 있습니다. 반면에 touch외부 바이너리가 있습니다.

$ type echo
echo is a shell builtin
$ type touch
touch is hashed (/usr/bin/touch)

쉘 내장 함수fork프로그램을 로드할 때 오버헤드가 발생하지 않기 때문에 훨씬 빠릅니다 exec. 따라서 내장 명령과 외부 명령을 여러 번 실행할 때 상당한 시간 차이를 관찰하게 됩니다.

time이것이 바로 이와 같은 유틸리티가 쉘 내장으로 제공되는 이유입니다.

다음을 사용하여 셸 내장 명령의 전체 목록을 얻을 수 있습니다.

enable -p

위에서 언급했듯이유용그리고내장결과적으로 심각한 성능 저하가 발생합니다. 다음은 약 9000개의 파일을 생성하는 데 걸리는 시간에 대한 통계입니다.내장 echo그리고유용 echo:

# Using builtin
$ time bash -c 'for i in {1000..9999}; do echo > $i; done'

real    0m0.283s
user    0m0.100s
sys 0m0.184s

# Using utility /bin/echo
$ time bash -c 'for i in {1000..9999}; do /bin/echo > $i; done'

real    0m8.683s
user    0m0.360s
sys 0m1.428s

관련 정보