为什么'for'循环比'while'循环更快地从文件中读取?

时间:2013-09-17 02:40:52

标签: bash performance loops for-loop while-loop

前言

我一直被告知,在shell中工作时,最好在while循环上执行for循环,并且不应该使用for循环来执行命令替换cat发送文件。我的理解是,有很多原因,包括:

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

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

测试设置:

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

测试结果

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编程指南(一些快速的谷歌搜索并没有产生我多年前阅读大部分内容的确切位置。)

1 个答案:

答案 0 :(得分:4)

这里的区别在于,在$(cat testfile)情况下,您正在将ENTIRE测试文件一次性读入内存并对其进行字符串拆分,而在while read情况下,您正在读取一行一段时间。

当然,较少数量的大读取更有效。

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