在两个命令之间的管道中添加一个大缓冲区

33

假设有一个类似于bash命令行的格式:

commandA | commandB

我想在commandAcommandB之间添加一个大小约为1MB的缓冲区。 我期望可以通过以下方式实现:

commandA | BUFFER | commandB

但是,使用哪个命令来使用BUFFER

备注:我想这样做是为了解耦两个命令,使它们更好地并行化。问题在于commandB以大块处理数据,这意味着commandA会阻塞,直到commandB完成一个块。所以一切都是按顺序运行的 :-(

6个回答

30

BUFFER 被称为缓冲区。(man 1 buffer,也许需要进行 apt-get install buffer 安装)


应该向缓冲区传递哪些选项以获得例如1GB的缓冲区大小?似乎有许多选项可配置块大小、块数和其他内容,但我不清楚要使用哪些选项来获取给定大小的简单缓冲区。 - Suzanne Soy
2
“-m size” 是用于总大小的。如果您需要更细粒度的控制,请同时使用“-s blocksize -b blocks”。 - Eugen Rieck

26

还有另一个工具,pv - 管道查看器:

process1 | pv -pterbTCB 1G | process2
  • B参数指定缓存大小,这里为1 GB
  • C禁用splice,这是由于B参数所需的
  • T显示缓存级别
  • pterb是由于T存在而需要的默认显示开关

pv在官方仓库中不存在(例如arch linux),可能会在一些系统上提供替代mbuffer/buffer


1
我尝试使用pv作为缓冲区,但当其输出阻塞而缓冲区未满时,它有时会停止读取其输入。这似乎是一个错误,使用strace附加可以解决它。带有缓冲区的pv还会在每100毫秒或直到没有更多数据可用时在读和写之间切换,但是当我尝试时,它减慢了从磁盘读取的速度。我想100毫秒的间隔对于系统继续预读来说太长了。 - JanKanis
-pterbTCB 1G 是很好的默认选项。应该在手册中说明! - undefined

8

您可以使用

  • 缓冲区(已经提到)
  • mbuffer(在Solaris上也可用,可能还适用于其他UNIX操作系统)

例如:

    process1 | mbuffer -m 1024M | process2

使用1G缓冲区


mbuffer似乎比buffer更好,因为根据manpage和我的实验,buffer仅限于1GB。 - phihag

4
该程序buffer使用共享内存,这可能会成为问题,因为在出现错误的情况下,内存可能会泄漏,因为共享内存可以超越分配内存的程序的生命周期。另一种选择可能是GNU的dd
commandA |
dd status=none iflag=fullblock bs=1M |
commandB

使用fullblock选项非常重要。否则,在从管道读取时,dd可能会导致数据丢失。

解释dd的参数

  • status=none

    设置要打印到stderr的信息级别;'none' 除了错误消息之外,抑制所有内容。

  • iflag=fullblock

    累计完整的输入块

  • bs=1M

    一次读写最多一兆字节(默认值:512字节);


0

有一种工具叫做stdbuf,可以让你指定管道的缓冲区大小,类似于:

stdbuf -o 1M commandA | commandB

-4

或者你可以使用命名管道并行运行它们:

mkfifo myfifo
commandB < myfifo &
commandA > myfifo
rm myfifo

1
仅缓冲约64KB - 不大。 - Volker Siegel
2
这个解决方案的缓冲区大小与 commandA | commandB 相同。 - mik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接