bash 管道中的缓冲区如何在 linux 上工作?

Wil*_*ill 3 linux bash pipe

想象一个简单的命令如下:

cmd1 | cmd2
Run Code Online (Sandbox Code Playgroud)

是否cmd2开始执行

  1. 一旦cmd1输出一些东西
  2. 还是只有cmd1完全完成并退出?

在第 1 种情况下,当cmd1输出速度比cmd2消耗速度快时,或者只是在第 2 种情况下,中间输出必须有一个缓冲区。

  1. 该缓冲区位于何处?它是在内存中还是在磁盘上?
  2. 是否可以配置缓冲区的位置和大小?
  3. 当缓冲区不够大时会发生什么?

Wyz*_*a-- 6

该cmd2程序开始立即执行,但每当它试图读取输入时,它会“阻止”(停止并等待),如果需要的话,直到一些可用。这是由内核自动完成的。除此之外,这两个程序可以同时运行(包括同时在不同的 CPU 内核上运行)。

两个进程之间的缓冲区由内核持有,它在内存中(尽管它可能会被分页——我不确定)。在默认的缓冲区的大小似乎没有可配置的,但是程序可以请求指定的管更大的尺寸,而对于限制是可配置通过写/proc/sys/fs/pipe-max-size文件(在是/proc,是不是其实是一个磁盘上的文件;它是访问内核中设置的虚拟文件。)有关更多信息,请参阅此问题。

如果cmd1尝试写入但缓冲区已满,它将阻塞,直到缓冲区中有可用空间(当cmd2读取某些缓冲数据时会发生这种情况)。因此,如果cmd1产生输出太快,则必须等待cmd2消耗输出,因此会自动减慢速度。

如果缓冲区很小,程序在等待它时可能会更频繁地阻塞,这会使它们需要更长的时间才能完成,因为它们将花费更多的时间等待。

一般来说,大多数管道可能分为两类:

  • cmd1产生输出比cmd2消耗它更快:缓冲区通常已满(或接近它)并且cmd1在尝试写入时经常阻塞,这会减慢速度以匹配cmd2. cmd2能够全速运行,因为输入总是在缓冲区中可用,因此它很少在读取时发生阻塞。
  • cmd2消耗输入比cmd1产生它更快:缓冲区通常是空的(或接近它),并且cmd2在尝试读取时经常阻塞,这会减慢速度以匹配cmd1. cmd1能够全速运行,因为总是有空间可用于写入缓冲区,因此它很少在写入时发生阻塞。