디렉터리에 있는 모든 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
. 이를 사용하면 각 파일 실행에 대해 새 프로세스를 시작하는 것과 관련된 커널 오버헤드가 제거됩니다.touch
echo
touch
그러나 이 효과를 얻는 가장 빠른 방법은 여전히 을 사용하는 것이지만 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