Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 为什么a';对于';循环速度比';而';从文件读取的循环? 前言:_Bash_Performance_Loops_For Loop_While Loop - Fatal编程技术网

Bash 为什么a';对于';循环速度比';而';从文件读取的循环? 前言:

Bash 为什么a';对于';循环速度比';而';从文件读取的循环? 前言:,bash,performance,loops,for-loop,while-loop,Bash,Performance,Loops,For Loop,While Loop,我一直被教导,在shell中工作时,最好在循环时执行,而在上循环for循环,并且不应在文件中使用for循环和命令替换cat。我的理解是,这有很多原因,包括: for循环要求一次将要处理的所有数据加载到内存中 对于循环,默认情况下会在空白处而不是换行符上进行分词,因此除了必须将文件中的所有内容都存储在内存中之外,还需要进行更多的分词操作,以占用内存 for循环在您的in语句中的所有内容都完成加载之前,不会从“do”的右侧开始处理,这意味着在等待结果的部分时间里,在“预加载”时实际上什么都没有发生

我一直被教导,在shell中工作时,最好在
循环时执行
,而
上循环
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