我想知道 tee 是否会减慢管道速度。毕竟,将数据写入磁盘比通过管道传送数据要慢。
tee 是否会等待将数据发送到下一个管道,直到数据写入磁盘? (如果没有,我猜 tee 必须对已发送但未写入磁盘的数据进行排队,这对我来说听起来不太可能。)
$ program1 input.txt | tee intermediate-file.txt | program2 ...
答案1
是的,它会减慢速度。它基本上确实有一个未写入数据的队列,尽管这实际上是由内核维护的——所有程序都有这个队列,除非它们明确提出其他要求。
例如,这是一个使用 的简单管道pv
,这很好,因为它显示传输速率:
$ pv -s 50g -S -pteba /dev/zero | cat > /dev/null
50GiB 0:00:09 [ 5.4GiB/s] [===============================================>] 100%
现在,让我们tee
在其中添加一个,甚至不需要编写额外的副本 - 只需将其转发即可:
$ pv -s 50g -S -pteba /dev/zero | tee | cat > /dev/null
50GiB 0:00:20 [2.44GiB/s] [===============================================>] 100%
所以,这有点慢,而且它甚至没有做任何事情!这是 tee 内部将 STDIN 复制到 STDOUT 的开销。 (有趣的是,pv
在其中添加第二个仍保持在 5.19GiB/s,因此pv
比tee
.pv
使用快得多splice(2)
,tee
但可能不会。)
不管怎样,让我们看看如果我告诉tee
写入磁盘上的文件会发生什么。它开始时相当快(约 800MiB/s),但随着时间的推移,它会不断减慢,最终降至约 100MiB/s,这基本上是磁盘写入带宽的 100%。 (快速启动是由于内核缓存了磁盘写入,而磁盘写入速度减慢是内核拒绝让缓存无限增长。)
有关系吗?
以上是最坏的情况。上面使用管道尽可能快地喷出数据。我能想到的唯一现实世界的用途是将原始 YUV 数据传输到/从ffmpeg
.
当您以较慢的速率发送数据时(因为您正在处理它们等),其影响将会小得多。
答案2
毕竟这里没什么奇怪的
>POSIX 说,
描述
这球座实用程序应将标准输入复制到标准输出,在零个或多个文件中进行复制。这球座实用程序不应缓冲输出。
和还有那个
基本原理
缓冲要求意味着 tee 不允许使用 ISO C 标准完全缓冲或行缓冲写入。这并不意味着 tee 必须先执行 1 字节读取,然后执行 1 字节写入。
因此,在不解释“基本原理”的情况下,tee
可能只会读取和写入不管多少字节一次可以放入管道缓冲区,在每次写入时刷新输出。
是的,根据应用程序的不同,这可能效率相当低——所以请随意删除/注释掉其中的任何一个:
https://github.com/coreutils/coreutils/blob/master/src/tee.c#L208
https://github.com/coreutils/coreutils/blob/master/src/tee.c#L224