Bash 为什么a';对于';循环速度比';而';从文件读取的循环? 前言:
我一直被教导,在shell中工作时,最好在Bash 为什么a';对于';循环速度比';而';从文件读取的循环? 前言:,bash,performance,loops,for-loop,while-loop,Bash,Performance,Loops,For Loop,While Loop,我一直被教导,在shell中工作时,最好在循环时执行,而在上循环for循环,并且不应在文件中使用for循环和命令替换cat。我的理解是,这有很多原因,包括: for循环要求一次将要处理的所有数据加载到内存中 对于循环,默认情况下会在空白处而不是换行符上进行分词,因此除了必须将文件中的所有内容都存储在内存中之外,还需要进行更多的分词操作,以占用内存 for循环在您的in语句中的所有内容都完成加载之前,不会从“do”的右侧开始处理,这意味着在等待结果的部分时间里,在“预加载”时实际上什么都没有发生
循环时执行,而在上循环for
循环,并且不应在文件中使用for
循环和命令替换cat
。我的理解是,这有很多原因,包括:
for
循环要求一次将要处理的所有数据加载到内存中
对于
循环,默认情况下会在空白处而不是换行符上进行分词,因此除了必须将文件中的所有内容都存储在内存中之外,还需要进行更多的分词操作,以占用内存
for
循环在您的in
语句中的所有内容都完成加载之前,不会从“do”的右侧开始处理,这意味着在等待结果的部分时间里,在“预加载”时实际上什么都没有发生
然而,在做一些简单的测试时,我发现虽然循环的内存消耗似乎更大(正如预期的那样),但是而循环的实际性能更低。这并不是一个很大的区别,在任何现代机器上,这可能会开始起作用,我可能会切换到awk或python,但我仍然很好奇为什么会发生这种情况
测试设置:
我做了一系列简单的测试,只是将文件中的行回显到/dev/null中。我的输入是两个平面文件,分别包含100K和1Mil IP地址。在我下面的输出中是一个测试,但我运行了几次,每次都有类似的结果。我是在2013年的MBA(i7,8g Mem)上进行这项测试的
测试结果
Ds MacBook Air:i的时间约为d$,单位为$(cat/tmp/ips.100k);do echo$i>/dev/null;完成
实0m1.629s
用户0m1.154s
sys 0m0.480s
Ds MacBook Air:~d$时间,单位为$(cat/tmp/ips.mill);do echo$i>/dev/null;完成
真正的0m17.567s
用户0m12.414s
sys 0m5.131s
Ds MacBook Air:~d$阅读时的时间;do echo$i>/dev/null;完成/dev/null;完成==>/tmp/ips.100k/tmp/ips.mill这里的区别是,在$(cat testfile)
情况下,您一次将整个测试文件读取到内存中,并将其字符串拆分,而在while read
情况下,您一次读取一行
当然,较小数量的大型读取更有效
$(cat testfile)
方法也引入了一些bug,它将字符串拆分(您知道)并全局扩展(您可能不知道)文件内容——也就是说,如果您有一个*
,它可以被当前目录中的文件列表所替换。$(…顺便说一句,在freenode的#bash中,我们倾向于警告人们不要使用TLDP的文档,特别是ABS——虽然它通常不是完全错误的,但它经常显示导致bug的错误做法。是更仔细地策划和积极维护的文档。如果将重定向重构到..;done>/dev/null
相反?@tripleee我希望这能全面提高性能,但不会改变for-vs-while增量(假定对for循环进行相同的转换)。在我看来,磁盘操作的数量在这里并不是那么重要。如果是,echo“$(
应接近i的,单位为$(
。然而,我只得到了一点小小的改进。虽然read
是内置的,但我想它的重复执行会减慢循环。@Socowi,更重要的是read
一次读取一个字节,所以无论是从FIFO还是从文件读取,都需要大量的系统调用。echo$(
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