将千兆字节的数据写入管道时会发生什么?

整洁的

假设我有一个名为的配方的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,或者只是谨慎地这样做,当缓冲区空间用尽时来自writesyscallyes最终将根本不会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一侧最终终止时,yesSIGPIPE作为写入管道的结果而发送,另一端没有剩余任何内容。然后,根据yes实现的不同,这将调用其自己的信号处理程序或默认的内核信号处理程序,它将终止。


*在简单的情况下,接收方以与写入数据大致相同的速率处理数据,通过使用虚拟内存映射和提供写入过程中的物理页面,此传输也可以零复制而没有中间缓冲区可供接收者使用。但是,您所描述的情况肯定会最终需要使用管道缓冲区来存储未读取的数据。

**也有可能使用O_NONBLOCK文件描述符上设置标志来完成写入,这将启用非阻塞模式。在这种情况下,您可能会得到一个不完整的写入,然后写入将返回EAGAIN,应用程序将需要自行处理。它可能会通过挂起或运行其选择的其他代码来处理管道已满的方式来做到这一点。yes但是,对于我能找到的每个现代版本以及大多数其他应用程序,上面的描述都是会发生的,因为它们没有使用O_NONBLOCK

***应用程序在收到后可以做任何喜欢的事情SIGPIPE-从理论上讲,它甚至可能决定不终止。但是,所有常见yes用法使用默认SIGPIPE处理程序,该处理程序仅在不执行任何更多用户空间指令的情况下终止。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

将变量绑定到某些数据时会发生什么?

来自分类Dev

为什么将VideoClip的帧写入视频文件时会发生变化?

来自分类Dev

通过旧的CAT5电缆连接千兆交换机时会发生什么?

来自分类Dev

在Windows上写入aux文件时会发生什么?

来自分类Dev

为什么在文件中写入csv时会发生错误?

来自分类Dev

写入设备驱动程序时会发生什么?

来自分类Dev

将1Byte数据转换为4Byte时会发生什么情况

来自分类Dev

暂停时会发生什么?

来自分类Dev

RTCP数据包丢失时会发生什么?

来自分类Dev

将数据管道传输到bash时,“ $ 0”会发生什么

来自分类Dev

将函数用作参数时会发生什么情况?

来自分类Dev

当我将%esp移至%ebp时会发生什么?

来自分类Dev

按命令进行管道和输入重定向时会发生什么

来自分类Dev

当两个进程写入mmaped文件的相同部分时会发生什么?

来自分类Dev

当多个进程尝试写入同一文件时会发生什么?

来自分类Dev

当您写入具有相同配置的寄存器时会发生什么?

来自分类Dev

当我们向GPIO写入0时会发生什么

来自分类Dev

当我写入随机存储器地址时会发生什么?

来自分类Dev

当多个进程尝试写入同一文件时会发生什么?

来自分类Dev

当所有数据节点都在hadoop中发生故障时会发生什么?

来自分类Dev

未指定dbCreate时会发生什么?

来自分类Dev

升级Ubuntu时会发生什么?

来自分类Dev

单击提交按钮时会发生什么

来自分类Dev

循环结束时会发生什么?

来自分类Dev

合成子类的变量时会发生什么?

来自分类Dev

达到墓碑限制时会发生什么

来自分类Dev

VRAM已满时会发生什么?

来自分类Dev

当指针太大时会发生什么?

来自分类Dev

断言检查失败时会发生什么?

Related 相关文章

  1. 1

    将变量绑定到某些数据时会发生什么?

  2. 2

    为什么将VideoClip的帧写入视频文件时会发生变化?

  3. 3

    通过旧的CAT5电缆连接千兆交换机时会发生什么?

  4. 4

    在Windows上写入aux文件时会发生什么?

  5. 5

    为什么在文件中写入csv时会发生错误?

  6. 6

    写入设备驱动程序时会发生什么?

  7. 7

    将1Byte数据转换为4Byte时会发生什么情况

  8. 8

    暂停时会发生什么?

  9. 9

    RTCP数据包丢失时会发生什么?

  10. 10

    将数据管道传输到bash时,“ $ 0”会发生什么

  11. 11

    将函数用作参数时会发生什么情况?

  12. 12

    当我将%esp移至%ebp时会发生什么?

  13. 13

    按命令进行管道和输入重定向时会发生什么

  14. 14

    当两个进程写入mmaped文件的相同部分时会发生什么?

  15. 15

    当多个进程尝试写入同一文件时会发生什么?

  16. 16

    当您写入具有相同配置的寄存器时会发生什么?

  17. 17

    当我们向GPIO写入0时会发生什么

  18. 18

    当我写入随机存储器地址时会发生什么?

  19. 19

    当多个进程尝试写入同一文件时会发生什么?

  20. 20

    当所有数据节点都在hadoop中发生故障时会发生什么?

  21. 21

    未指定dbCreate时会发生什么?

  22. 22

    升级Ubuntu时会发生什么?

  23. 23

    单击提交按钮时会发生什么

  24. 24

    循环结束时会发生什么?

  25. 25

    合成子类的变量时会发生什么?

  26. 26

    达到墓碑限制时会发生什么

  27. 27

    VRAM已满时会发生什么?

  28. 28

    当指针太大时会发生什么?

  29. 29

    断言检查失败时会发生什么?

热门标签

归档