关于管道的几个问题

时间:2018-02-01 00:32:36

标签: perl pipe

这是process hangs when writing large data to pipe的后续行动,我们在其中发现了如何使用管道的问题。评论中有一个有用的讨论,但我有更多的问题,所以在这里提出它们。

如果你必须假设一种编程语言假设Perl,那就是我使用的(所以我将保留标签)。我不知道这有多少因语言而异......

  1. " flush"的定义是什么?究竟?在冲洗之前,是数据 在管道中,或者只是在刷新后管道中的数据?

    1a上。如果它还没在管道中,它在哪里?

    1b中。如果管道中 ,那么读者如何无法阅读?

  2. 拥有冲洗概念的原因/动机是什么?

  3. 根据对早期帖子的评论:"管道被“缓冲”'好东西 一个块(4kB?)写入或管道已满(64kB?)"一旦管道装满,管道会自动冲洗吗?

  4. 如果要将单个变量写入大于管道整个大小的管道,该怎么办?假设你还有一个主动读取管道的进程,那么这个进程是否足够聪明,可以将变量写入块中,还是会冻结,因为它不能将变量全部放入管道中?

1 个答案:

答案 0 :(得分:3)

让我们从#2开始。输出手柄的缓冲和冲洗是关于效率的。磁盘或套接字写操作有一些开销,一般来说,在单个操作中写入1000个字节比在250个单独的操作中写入4个字节更有效。对于I / O较多但计算较轻的程序,这可能会产生巨大的差异。所以I / O库维护一个内存"缓冲区"具有选择的尺寸以获得最佳书写效率。我们假设 4 8KB。

在正常的缓冲操作中,您的进程会将一些字节写入输出句柄。 I / O库将这些字节复制到"缓冲区"直到缓冲区已满。当缓冲区已满时,I / O库会对整个缓冲区的管道/套接字/磁盘执行实际写入操作。然后它擦除缓冲区并等待更多输出。

(输入缓冲也是一件事。就像你可能从输入句柄要求23个字节,I / O库可能从输入通道读取8KB数据,返回23个字节给你,然后把剩下的进入内存以进行下一次读取请求)

所以现在我们将讨论#1。缓冲的一个明显缺点是,表面上写入文件/管道/套接字的字节可能只存在于缓冲区中,因此不能用于读取相同数据源的单独进程,并且您遇到{{3 }}。读取器无法使用的数据量可能与输出句柄上缓冲区的大小一样大。

A" flush"输出句柄上的操作告诉I / O库将当前缓冲区写入磁盘/管道/套接字,即使缓冲区未满。这确实使数据可供单独的读者使用。

在Perl中,输出句柄可以自动刷新",这意味着在句柄上每次写入或打印后都将执行刷新操作。使用自动清洗功能,您会因I / O缓冲而失去效率,但您可以从输出生成器获得更好的响应速度。默认情况下,大多数句柄不会自动刷新,因此您必须使用

之类的调用自行启用它
WRITER->autoflush(1)
创建输出句柄后

。如果没有autoflush,只有在输出缓冲区已满或输出句柄关闭时才会写入输出。

#3。管道和套接字也具有有限的容量,这与我们一直在谈论的I / O缓冲区的大小无关(文件也具有有限的容量,因为你最终会耗尽磁盘空间)。如果已将足够的输出写入管道或套接字以使其已满,则写入操作将被阻止。当其他进程从中读取时,管道和套接字可能会被清空。当有足够的容量来包含写操作的内容时,操作将继续。原则上,您可以在输出句柄上写入管道的容量(让我们说64KB)加上输出句柄缓冲区的大小(~8KB),然后再进行操作块。

#4。那么,如果您尝试对管道进行一次非常大的写入会发生什么?这取决于,但不能保证它会有任何好处。所以最好不要那样做。对于进程间数据量相对于管道容量较大的用例,请考虑使用文件。