假设我有一个名为的配方的makefile,hour_long_recipe
顾名思义,该文件需要一个小时才能运行。在整个食谱中的随机点,它会询问是/否的问题。假设它总共要问10个问题。
一种可能的(并且经常推荐)运行它的方法是:
yes | make hour_long_recipe
用回答所有问题y
。但是,据我了解,无论是否实际使用其stdin中的数据,它都可以每秒高达10.2 GiB的速度yes
输出到其stdout 。make
即使只有10 MiB / s(比任何yes
相信Reddit线程的实现都要慢得多),在一个小时的过程中,它总共也将超过35 GiB,其中只有20个字节将被读取。数据去哪儿了?可以将其保存到磁盘,但这很浪费,而且如果磁盘填充得足够快,它甚至可能导致make
故障。
大概操作系统将阻止它实现这一目标,但是怎么办呢?限制是什么?当达到该限制时会发生什么?
tl; dr:yes
如果不从另一侧读取数据,则在某个时候将被阻止写入。在读取数据或接收到信号之前,它将无法继续执行,因此您通常不必担心yes
写入千兆字节和几千兆字节的数据。
要记住的重要一点是,管道是FIFO数据结构,而不是单纯的流,如果不立即在接收器上读取数据,流将丢弃数据。也就是说,尽管在大多数情况下它似乎是从书写应用程序到阅读应用程序的无缝数据流,但它确实需要中间存储来执行,并且中间存储的大小是有限的。*
如果我们查看pipe(7)手册页,我们可以阅读以下有关内部缓冲区大小的信息(添加了重点):
在2.6.11之前的Linux版本中,管道的容量与系统页面大小相同(例如,在i386上为4096字节)。从Linux 2.6.11开始,管道容量为16页(即,在页面大小为4096字节的系统中为65,536字节)。从Linux 2.6.35开始,默认管道容量为16页,但是可以使用fcntl(2)F_GETPIPE_SZ和F_SETPIPE_SZ操作查询和设置容量。
假设您使用的是标准的x86_64系统,则很有可能使用4KiB页面,因此,除非在使用管道的任何一端,否则管道容量的2 ^ 16上限很可能是正确的fcntl(F_SETPIPE_SZ)
。无论哪种方式,原理都成立:管道两侧之间的中间存储是有限的,并存储在内存中。
在抽象管道中a | b
,此存储空间用于a
写入一些数据和b
实际读取它们之间的时间段。那么,假设您的make
调用(以及通过继承也连接到此管道的任何子级)实际上并没有尝试读取stdin,或者只是谨慎地这样做,当缓冲区空间用尽时,来自的write
syscallyes
最终将根本不会yes
从睡眠中唤醒。yes
当缓冲区空间再次可用或接收到信号时,它将等待唤醒。**所有这些都由内核的进程调度程序处理。您可以在中看到此内容pipe_write()
,它是write()
管道的处理程序:
static ssize_t
pipe_write(struct kiocb *iocb, struct iov_iter *from)
{
/* ... */
if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
wake_next_writer = false;
if (wake_next_writer)
wake_up_interruptible_sync_poll(&pipe->wr_wait, EPOLLOUT | EPOLLWRNORM);
/* ... */
}
当make
一侧最终终止时,yes
将SIGPIPE
作为写入管道的结果而发送,另一端没有剩余任何内容。然后,根据yes
实现的不同,这将调用其自己的信号处理程序或默认的内核信号处理程序,它将终止。
*在简单的情况下,接收方以与写入数据大致相同的速率处理数据,通过使用虚拟内存映射和提供写入过程中的物理页面,此传输也可以零复制而没有中间缓冲区可供接收者使用。但是,您所描述的情况肯定会最终需要使用管道缓冲区来存储未读取的数据。
**也有可能使用O_NONBLOCK
文件描述符上设置的标志来完成写入,这将启用非阻塞模式。在这种情况下,您可能会得到一个不完整的写入,然后写入将返回EAGAIN
,应用程序将需要自行处理。它可能会通过挂起或运行其选择的其他代码来处理管道已满的方式来做到这一点。yes
但是,对于我能找到的每个现代版本以及大多数其他应用程序,上面的描述都是会发生的,因为它们没有使用O_NONBLOCK
。
***应用程序在收到后可以做任何喜欢的事情SIGPIPE
-从理论上讲,它甚至可能决定不终止。但是,所有常见yes
用法都使用默认SIGPIPE
处理程序,该处理程序仅在不执行任何更多用户空间指令的情况下终止。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句