我正在编写一个脚本,为了提高可读性,我正在考虑更换&#39 ;;'在我的sed表达式中的一个管道。
例如
sed 's/.*@@//;s/[[:space:]].*//;s/\(.*\\\).*/\1LATEST/'
会变成
sed 's/.*@@//' | sed 's/[[:space:]].*//' | sed 's/\(.*\\\).*/\1LATEST/'
我知道管道有成本,但我想是&#39 ;;'在sed也有成本。
它可以等同吗?如果没有,在数千次迭代的循环中有多糟糕?
答案 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倍。