我有一个非常漫长而复杂的shell管道设置来获取2.2Gb的数据并对其进行处理。目前需要45分钟才能完成。管道是捆绑在一起的一些cut,grep,sort,uniq,grep和awk命令。我怀疑是grep部分导致它花了这么多时间,但我无法确认它。
无论如何要从一端到另一端“分析”整个管道,以确定哪个组件最慢,如果它是CPU或IO绑定,那么它可以进行优化吗?
我不能在这里发布整个命令,因为它需要发布专有信息,但我怀疑它是以下位用htop检查它:
grep -v ^[0-9]
答案 0 :(得分:5)
这样做的一种方法是逐步建立管道,对每次添加进行计时,并尽可能多地取出等式(例如输出到终端或文件)。一个非常简单的例子如下所示:
pax:~$ time ( cat bigfile >/dev/null )
real 0m4.364s
user 0m0.004s
sys 0m0.300s
pax:~$ time ( cat bigfile | tr 'a' 'b' >/dev/null )
real 0m0.446s
user 0m0.312s
sys 0m0.428s
pax:~$ time ( cat bigfile | tr 'a' 'b' | tail -1000l >/dev/null )
real 0m0.796s
user 0m0.516s
sys 0m0.688s
pax:~$ time ( cat bigfile | tr 'a' 'b' | tail -1000l | sort -u >/dev/null )
real 0m0.892s
user 0m0.556s
sys 0m0.756s
如果您将上述用户和系统时间相加,您会看到增量增加为:
cat
;
{li> 0.436(0.312 + 0.428 - 0.304)秒tr
;
{li> 0.464(0.516 + 0.688 - 0.436 - 0.304)秒tail
;和
sort
。这告诉我要研究的主要内容是tail
和tr
。
现在很明显,这只适用于CPU,我可能应该在每个阶段进行多次运行以达到平均目的,但这是我将采取的基本第一种方法。
如果事实证明它确实是您的grep
,那么您可以使用其他一些选项。还有许多其他命令可以删除不以数字开头的行但你可能发现用于执行此操作的自定义命令可能更快,伪代码(未经测试,但你应该得到)这个想法):
state = echo
lastchar = newline
while not end of file:
read big chunk from file
for every char in chunk:
if lastchar is newline:
if state is echo and char is non-digit:
state = skip
else if state is skip and and char is digit:
state = echo
if state is echo:
output char
lastchar = char
这样的自定义目标代码有时可以比通用正则表达式处理引擎更高效,因为它可以针对特定情况进行优化。在这种情况下是否属实,或者任何案例,是您应该测试的。我的头号优化口头禅是衡量,不要猜测!
答案 1 :(得分:4)
经过一些进一步的实验后,我自己发现了这个问题。它似乎是由于grep中的编码支持。使用以下挂起管道:
grep -v ^[0-9]
我用sed替换它如下,它在45秒内完成!
sed '/^[0-9]/d'
答案 2 :(得分:1)
使用 zsh :
可以直接进行zsh-4.3.12[sysadmin]% time sleep 3 | sleep 5 | sleep 2
sleep 3 0.01s user 0.03s system 1% cpu 3.182 total
sleep 5 0.01s user 0.01s system 0% cpu 5.105 total
sleep 2 0.00s user 0.05s system 2% cpu 2.121 total