bash - 为什么 'for' 循环比从文件读取的 'while' 循环更快?

标签 bash performance loops for-loop while-loop

前言:

我一直被教导说,在 shell 中工作时,最好在 for 循环上执行 while 循环,并且你不应该使用 for 循环与命令替换 cat 文件。我的理解是,造成这种情况的原因有很多,包括:

  • for 循环需要一次将所有要处理的数据加载到内存中
  • for 循环默认在空格而不是换行符上进行分词,所以除了必须将文件中的所有内容都放在内存中之外,您还会有更多的分词占用内存
  • for 循环不会开始处理“在 do 的右边”,直到您的 in 语句中的所有内容都完成加载,这意味着部分时间您正在等待结果,当您“预加载”时实际上没有发生任何事情。

然而,在做一些简单的测试时,我发现虽然内存消耗在 for 循环中似乎更大(正如预期的那样),但 while 循环的实际性能是降低。这并不是一个巨大的差异,而且在任何现代机器上这可能开始变得重要的规模,我可能会切换到 awk 或 python,但我仍然很好奇为什么会这样。

测试设置:

我做了一系列简单的测试,只是将文件的行回显到/dev/null 中。我的输入是两个分别包含 100K 和 1Mil IP 地址的平面文件。在我下面的输出中是一个测试,但我运行了几次,每次都得到了相似的结果。我在 2013 MBA(i7、8g 内存)上运行此测试。

测试结果

Ds-MacBook-Air:~ d$ time for i in $(cat /tmp/ips.100k);do echo $i > /dev/null;done

real    0m1.629s
user    0m1.154s
sys 0m0.480s
Ds-MacBook-Air:~ d$ time for i in $(cat /tmp/ips.mill);do echo $i > /dev/null;done

real    0m17.567s
user    0m12.414s
sys 0m5.131s
Ds-MacBook-Air:~ d$ time while read i;do echo $i > /dev/null;done < /tmp/ips.100k

real    0m2.148s
user    0m1.493s
sys 0m0.655s
Ds-MacBook-Air:~ d$ time while read i;do echo $i > /dev/null;done < /tmp/ips.mill

real    0m21.536s
user    0m14.915s
sys 0m6.617s

Ds-MacBook-Air:~ d$ tail -5 /tmp/ips.100k /tmp/ips.mill
==> /tmp/ips.100k <==
1.1.134.155
1.1.134.156
1.1.134.157
1.1.134.158
1.1.134.159

==> /tmp/ips.mill <==
1.15.66.59
1.15.66.60
1.15.66.61
1.15.66.62
1.15.66.63

Ds-MacBook-Air:~ d$ wc -l /tmp/ips.100k /tmp/ips.mill
  100000 /tmp/ips.100k
 1000000 /tmp/ips.mill
 1100000 total

对于我关于 for 循环与 while 循环的断言,我没有任何直接引用,但我特别提到了 ~~TLDP ~~ Wooldridge 文档,或其他 Bash 编程指南(一些快速谷歌搜索并没有提供我多年前阅读大部分内容的确切位置。)

最佳答案

这里的区别在于,在 $(cat testfile) 的情况下,您一次将整个测试文件读入内存并对其进行字符串拆分,而在 while read 如果你一次读一行。

理所当然的,越少的 large reads 越高效。

$(cat testfile) 方法也引入了错误,其中字符串拆分(您知道)和全局扩展(您可能不知道)文件内容 - - 也就是说,如果你有一个*,它可以被当前目录中的文件列表代替。

关于bash - 为什么 'for' 循环比从文件读取的 'while' 循环更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18840457/

相关文章:

javascript - 如何提高 Canvas 性能

菜单中的 C++ 循环

linux - 连接每四个文件,Linux

android - Bash:查找并替换脚本中的文本

java - Java 接口(interface)相对于抽象类的性能开销

java - 使用多少线程更好? ( java )

regex - sed 在第 n 次出现后替换任何内容

bash - 了解 bash *String* 比较

PHP 遍历对象数组给出了意想不到的结果

php - 一起使用 mysql_fetch_assoc 和 mysql_result 吗?