具有非常大输出的管道命令

具有非常大输出的管道命令

我想要tar一个目录并将结果写入stdout,然后将其通过管道传输到压缩程序,如下所示:

tar -cvf - /tmp/source-dir | lzip -o /media/my-usb/result.lz -

我一直使用管道来输出多行文本的命令。现在我想知道当我通过管道传输一个具有非常大输出的(快速)命令(例如,tar随后是一个非常慢的压缩命令)时会发生什么?会tar等待其输出被 消耗掉吗lzip?或者它只是尽可能快地将所有内容输出到 RAM?如果后者属实,那么对于低 RAM 系统来说这将是一场灾难。

答案1

当数据生产者 ( tar) 尝试太快地写入管道以使消费者 ( lzip) 没有时间读取所有数据时,它将堵塞直到lzip有时间阅读tar所写的内容。有一个与管道关联的小缓冲区,但其大小可能小于大多数tar档案的大小。不存在管道填满系统 RAM 的风险。

“阻塞”只是意味着当tar调用库函数(或等效函数)时,调用不会返回,直到数据被传递到管道缓冲区,如果读取速度很慢,write()这可能需要一些时间lzip相同的缓冲区。您应该能够在与 相比(假设实际上比 更快)的top地方看到这一点,其中tar会减慢速度并睡眠很多。lziptarlzip

因此你会不是使用管道填充大量 RAM。为此(如果您愿意),您可以pv在中间使用类似的东西,并带有一些大缓冲区(此处为千兆字节):

tar -cvf - /tmp/source-dir | pv --buffer-size 1G | lzip -o /media/my-usb/result.lz -

tar无论何时pv阻塞, 这仍然会阻塞。pv当缓冲区已满且无法写入时会阻塞lzip


相反的情况以类似的方式工作,即,如果管道的左侧缓慢写入右侧快速,则右侧的消费者将阻塞,read()直到有数据可从管道读取。

这(数据 I/O)是唯一同步参与管道的进程的东西。除了读取和写入(偶尔会在等待其他人读取或写入时发生阻塞)之外,它们将彼此独立运行。

答案2

GNU柏油--lzip选项“通过lzip过滤存档”,所以你可能想改用:

tar -cvf --lzip /media/my-usb/result.lz /tmp/source-dir

回答问题:在您的情况下,系统将使用默认的系统缓冲区大小正确管理管道。

相关内容