Shellredirect和文件I / O持续时间

我以三种不同的方式将一些输出redirect到一个文件,每个都显示不同的时间。

$ >/tmp/file ; time for i in {1..1000}; do for j in {1..1000}; do echo $i $j >> /tmp/file; done; done real 0m33.467s user 0m21.170s sys 0m11.919s $ >/tmp/file ; exec 3>/tmp/file; time for i in {1..1000}; do for j in {1..1000}; do echo $i $j >&3; done; done; exec 3>&- real 0m24.211s user 0m17.181s sys 0m7.002s $ >/tmp/file ; time for i in {1..1000}; do for j in {1..1000}; do echo $i $j; done; done >> /tmp/file real 0m17.038s user 0m13.072s sys 0m3.945s 

有人可以解释这里的差异。 我目前的理解/怀疑是:

  1. 第一是最慢打开/closures文件多次,而其他人只做一次。 是对的吗? 什么缓冲。 通常情况下,我希望所有的输出都得到缓冲,在这种情况下,我们不应该有这么大的时间差异。
  2. 第三,如果所有的输出只写在外循环的末尾,那么在循环仍然执行的时候,所有的输出都存储在哪里。 也许在记忆中。 这是否意味着如果我回应了很多东西,只能在最后写出来,那么我可以用尽内存。
  3. 第二更像第一或第三。 为什么它与这两者有很大的不同。

PS:我已经运行了上述命令几次,发现时间是一致的。 所以,我看到的差异一定是由于一些真实的原因。

  1. 第一个版本是echo $i $j >> /tmp/file的一百万倍,打开文件进行追加,写入并关闭它。

  2. 做一百万次echo $i $j >&3与之不同,因为它不会每次打开/关闭文件,而是写入文件描述符#3。 exec 3>/tmp/file打开文件进行写入,并将文件描述符保存为#3。 当现在有一个命令将其stdout重定向到文件描述符#3(echo后的>&3的效果)时,shell需要在执行该命令之前设置该重定向,然后将之前的分配恢复到stdout。

  3. 像这样>> /tmp/file重定向完整循环的输出对于shell来说更容易:它可以简单地执行echo命令而不需要设置额外的文件描述符。 它只改变一次stdout的分配。

关于缓冲:在所有这三种情况下,底层文件系统都会缓冲对物理文件的访问,所以在这个级别上没有区别。 另外,大多数Linux在/ tmp上都安装了tmpfs,这使得你无论如何都可以进行纯内存操作。 所以你不测量IO性能,而是执行shell命令。 您可以通过增加写入的字节数来证明这一点(将常数值添加到行echo记录):

 >/tmp/file ; time for i in {1..1000}; do for j in {1..1000}; do echo "1000000 $i $j" >> /tmp/file; done; done >/tmp/file ; exec 3>/tmp/file; time for i in {1..1000}; do for j in {1..1000}; do echo "1000000 $i $j" >&3; done; done; exec 3>&- >/tmp/file ; time for i in {1..1000}; do for j in {1..1000}; do echo "1000000 $i $j"; done; done >> /tmp/file 

在我的电脑上,这个时间与没有常量“1000000”的时间相同,但是将两倍的字节写入文件。