
ディレクトリ内のすべての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
しかし、これはシェル組み込み関数なので、シェル組み込み関数の実行にはまったくフォークは必要ありません。代わりに、現在のシェルはすべての操作を実行し、外部プロセスを作成しないため、非常に高速です。
以下は、シェル操作の2つの概要です。を使用すると、新しいプロセスを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
近いパラメータリストを使用して複数回実行されます(ほとんどのシステムでは)。
このアプローチのもう1つの利点は、元のループの場合ではなく、すべての空白文字を含むファイル名に強力であることです。
答え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