我在一个大文件上运行 sed,并使用pv实用程序查看它读取输入和写入输出的速度。尽管 pv 显示 sed 在大约 5 秒内读取输入并写入输出,但 sed 又过了 20-30 秒才退出。为什么是这样?
这是我看到的输出:
pv -cN source input.txt | sed "24629045,24629162d" | pv -cN output > output.txt
source: 2.34GB 0:00:06 [ 388MB/s] [==========================================================================================================>] 100%
output: 2.34GB 0:00:05 [ 401MB/s] [ <=> ]
Run Code Online (Sandbox Code Playgroud)
有两个原因。首先,你没有告诉它q
。
考虑:
seq 10 | sed -ne1,5p
Run Code Online (Sandbox Code Playgroud)
在这种情况下,虽然它只p
打印输入行的前半部分,但它仍然必须读取其余的输入行直到 EOF。反而:
seq 10|sed 5q
Run Code Online (Sandbox Code Playgroud)
它会立即退出那里。
您还需要处理每个进程之间的延迟。因此,如果pv
以 4kb 缓冲,并且sed
缓冲 4kb,那么最后一个pv
始终落后于输入 8kb。这个数字很可能比这个数字还要高。
您可以尝试-u
使用 GNU/BSD/AST 进行切换sed
,但这几乎肯定不会对大输入的性能有所帮助。sed
如果你用它来调用 GNU,-u
它将read()
针对输入的每个字节。我没有看过其他人在这种情况下会做什么,但我没有理由相信他们会做任何不同的事情。所有这三个文档-u
都表示无缓冲- 这是一个就流而言非常普遍理解的概念。
您可以做的另一件事是使用rite 命令和一个或多个命名的rite-file[s] 显式显示 line-buffersed
的输出。它仍然会减慢速度,但它可能会比其他选择更好。w
w
你可以用任何sed
类似的方法来做到这一点:
sed -n 'w outfile'
Run Code Online (Sandbox Code Playgroud)
sed
的w
rite 命令始终是立即的 - 它是无缓冲的输出。并且因为(默认情况下) sed
每个行周期应用一次命令,sed
所以即使在管道中间也可以轻松用于有效的行缓冲 I/O。这样,至少,你可以让第二个始终保持pv
最新状态,sed
例如:
pv ... | sed -n '24629045,24629162!w /dev/fd/1' | pv ...
Run Code Online (Sandbox Code Playgroud)
...虽然这假设一个系统提供/dev/fd/[num]
链接(也就是说:几乎任何基于 Linux 的系统 - 除了 Android - 以及许多其他系统)。如果所述链接的可用性失败,要做同样的事情,您可以显式地创建自己的管道,并将mkfifo
其用作最后一个pv
的标准输入,并将其命名为sed
的w
rite 文件。