为什么“回声”比“触摸”快得多?

为什么“回声”比“触摸”快得多?

我正在尝试将目录中所有 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

为什么 echo 比 touch 快这么多?

答案1

在 bash 中,touch是外部二进制文件,但是echo外壳内置:

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

由于touch是外部二进制文件,并且每个文件调用touch一次,因此 shell 必须创建 300,000 个 实例touch,这需要很长时间。

echo然而,它是一个 shell 内置函数,并且 shell 内置函数的执行根本不需要 fork。相反,当前 shell 会执行所有操作,并且不会创建任何外部进程;这就是它速度如此之快的原因。

以下是 shell 操作的两个概况。您可以看到,使用时花费了大量时间来克隆新进程touch。使用/bin/echo而不是内置的 shell 应该会显示出更具可比性的结果。


使用触摸

$ 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

正如其他人所回答的那样,使用命令比通常(尽管不要求)内置于 shell 中的命令echo更快。使用它可以免除与为您获得的每个文件运行启动新进程相关的内核开销。touchechotouch

但是,请注意,实现此效果的最快方法仍然是使用touch,但不是为每个文件运行一次程序,而是可以使用选项-execwithfind来确保仅运行几次。这种方法通常会更快,因为它避免了与 shell 循环相关的开销:

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

如果可能的话,使用+(而不是\;)withfind ... -exec仅运行该命令一次,并将每个文件作为参数。如果参数列表非常长(如 300,000 个文件的情况),将使用长度接近限制的参数列表进行多次运行(ARG_MAX在大多数系统上)。

这种方法的另一个优点是,它对于包含所有空白字符的文件名表现稳健,而原始循环的情况则不同。

答案3

echo是一个 shell 内置的。另一方面,touch是外部二进制文件。

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

Shell 内置函数速度要快得多,因为加载程序时不涉及任何开销,即不涉及fork/ exec。因此,在多次执行内置命令与外部命令时,您会观察到显着的时间差异。

time这就是像这样的实用程序可以作为 shell 内置程序使用的原因。

您可以通过以下命令获取 shell 内置命令的完整列表:

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

相关内容