使用管道代替时对Sed性能的影响;

时间:2018-05-08 12:37:57

标签: bash performance sed parallel-processing pipe

我正在编写一个脚本,为了提高可读性,我正在考虑更换&#39 ;;'在我的sed表达式中的一个管道。

例如

sed 's/.*@@//;s/[[:space:]].*//;s/\(.*\\\).*/\1LATEST/'

会变成

sed 's/.*@@//' | sed 's/[[:space:]].*//' | sed 's/\(.*\\\).*/\1LATEST/'

我知道管道有成本,但我想是&#39 ;;'在sed也有成本。

它可以等同吗?如果没有,在数千次迭代的循环中有多糟糕?

1 个答案:

答案 0 :(得分:2)

这实际上是一个有趣的问题。因为使用额外的流水线会占用更多的CPU处理时间,但由于并行化,可以更快地用于多核CPU上的大量输入。

案例#1:大输入

我使用以下命令构造输入并为命令计时:

time echo N | awk '{ for(i=0;i<$0;i++) print i"@@\n "i"\n"i"\\" }' | COMMAND > /dev/null

其中N是一个整数,告诉AWK测试输入应该有多长,而COMMAND是你想要计时的命令(或管道)。

我在2核机器上运行N = 10,000,000的测试:

单一版本:

time echo 10000000 | awk '{ for(i=0;i<$0;i++) print i"@@\n "i"\n"i"\\" }' | sed 's/.*@@//;s/[[:space:]].*//;s/\(.*\\\).*/\1LATEST/' > /dev/null

结果:

real    1m26.714s
user    1m35.196s
sys     0m1.212s

流水线sed版本:

time echo 10000000 | awk '{ for(i=0;i<$0;i++) print i"@@\n "i"\n"i"\\" }' | sed 's/.*@@//' | sed 's/[[:space:]].*//' | sed 's/\(.*\\\).*/\1LATEST/' > /dev/null

结果:

real    0m56.280s
user    1m46.404s
sys     0m0.972s

正如您所看到的,即使额外的管道增加了大约11秒的额外处理时间(用户+ sys),该命令实际上需要大约30秒的实时完成时间,因为三个sed命令中的每一个的输出都是当它仍在工作时由下一个处理。在我的机器上,它使实际处理时间几乎恰好是CPU时间的一半,这表明两个CPU核心的有效使用。

但是,对于单核机器,额外的流水线操作只会增加不必要的开销,从而减慢处理速度。

案例#2:逐行处理

另一方面,如果您正在编写bash脚本并使用sed命令处理单独的行which you should not do,则输出可能太小而无法观察上述并行化效果。而单一的sed版本会更有效率。

以下是一个一个地处理10,000行的时间:

time for ((i=1;i<=10000;i++)); do printf "$i@@\n $i\n$i\\ \n" | sed 's/.*@@//;s/[[:space:]].*//;s/\(.*\\\).*/\1LATEST/'; done > /dev/null

结果:

real    0m27.430s
user    0m2.772s
sys     0m4.224s

流水线sed:

time for ((i=1;i<=10000;i++)); do printf "$i@@\n $i\n$i\\ \n" | sed 's/.*@@//' | sed 's/[[:space:]].*//' | sed 's/\(.*\\\).*/\1LATEST/'; done > /dev/null

结果:

real    0m57.274s
user    0m3.704s
sys     0m7.776s

正如您所看到的,流水线sed比单个sed命令慢两倍以上。

请注意,在大输入上使用单个sed管道(如在案例#1中)比在线处理类似输入(如在案例#2中)快至少1000倍。