3

我设置了一个非常长且复杂的 shell 管道来获取 2.2Gb 的数据并对其进行处理。目前处理需要 45 分钟。管道是一些捆绑在一起的 cut、grep、sort、uniq、grep 和 awk 命令。我怀疑是 grep 部分导致它花费了这么多时间,但我无法确认。

无论如何要从端到端“分析”整个管道以确定哪个组件最慢以及它是否受 CPU 或 IO 限制,以便对其进行优化?

不幸的是,我不能在这里发布整个命令,因为它需要发布专有信息,但我怀疑它是用 htop 检查它的以下位:

grep -v ^[0-9]
4

3 回答 3

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

如果您将上面的用户和系统时间相加,您会看到增量增加是:

  • 0.304 (0.004 + 0.300) 秒cat
  • 0.436 (0.312 + 0.428 - 0.304) 秒tr
  • 0.464 (0.516 + 0.688 - 0.436 - 0.304) 秒tail;和
  • 0.108 (0.556 + 0.756 - 0.464 - 0.436 - 0.304) 秒为sort.

这告诉我要研究的主要内容是tailtr

现在显然,这仅适用于 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

像这样的自定义、有针对性的代码有时可以比通用的正则表达式处理引擎更高效,仅仅是因为它可以针对特定情况进行优化。无论是这种情况还是任何情况,您都应该测试一下。我的第一优化口头禅是衡量,不要猜测!

于 2011-10-10T13:10:55.093 回答
4

经过进一步的实验,我自己发现了这个问题。这似乎是由于 grep 中的编码支持。使用以下挂起管道:

grep -v ^[0-9]

我如下用 sed 替换它,它在 45 秒内完成!

sed '/^[0-9]/d'
于 2011-10-10T12:53:21.470 回答
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
于 2011-10-22T06:47:54.350 回答