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

时间:2018-07-21 02:34:39

标签: linux bash pipe

考虑以下简单命令:

cmd1 | cmd2

cmd2开始执行

  1. cmd1一经输出
  2. 还是仅在cmd1完全完成并退出后?

在情况1中,cmd1的输出速度比cmd2消耗的速度快,或者简单地在情况2中,中间输出必须有一个缓冲区。

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

2 个答案:

答案 0 :(得分:2)

  • library(tidyverse) df %>% group_by(id) %>% nest() ## A tibble: 4 x 2 # id data # <int> <list> #1 1 <tibble [3 × 6]> #2 2 <tibble [1 × 6]> #3 3 <tibble [1 × 6]> #4 4 <tibble [2 × 6]> df <- read.table(text = " id date x1 x2 x3 x4 x5 1 2009-01-01 5 4 2 5.5 7 1 2009-01-02 5.4 4.1 2.2 5.3 7.1 1 2009-01-03 4.4 2.1 4.2 6.3 10.1 2 2009-01-01 12.4 2.7 4.9 3.3 2.1 3 2010-01-01 3.4 1.7 4.6 4.3 6.1 4 2009-01-01 2.4 3.7 5.6 2.3 9.1 4 2009-01-02 3.4 5.7 7.6 3.3 5.1", header = T) 并行运行,都立即启动
  • 如果cmd1更快,它将在写入管道时阻塞。它不会继续写入,也不需要额外的缓冲区空间。
  • 如果cmd2更快,则会在读取管道时阻塞
  • 如果cmd1首先退出,则管道关闭,cmd2将其解释为文件结束并停止
  • 如果cmd1首先退出,则管道将关闭,并且cmd2将在下次写入时收到SIGPIPE,通常会杀死它。
  • 管道本身具有POSIX保证的4096字节,(当前)在Linux上为65536字节的内存中缓冲区空间。您不需要定期更改它。如果需要更多空间,请使用临时文件。

答案 1 :(得分:2)

cmd2程序立即开始运行,但是只要尝试读取输入,它将在必要时“阻塞”(停止并等待),直到有可用的为止。这是由内核自动完成的。除此之外,这两个程序可以同时运行(包括在不同的CPU内核上同时运行)。

两个进程之间的缓冲区由内核保存,并在内存中(尽管可能可以将其分页出来-我不确定)。缓冲区的 default 大小似乎不是可配置的,但是程序可以为特定管道请求更大的大小,并且 的限制可通过写以下命令来配置/proc/sys/fs/pipe-max-size文件(位于/proc中,实际上不是磁盘上的文件;它是访问内核中设置的虚拟文件。)有关更多信息,请参见this question

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

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

通常,大多数管道可能分为两类:

  • cmd1产生的输出要比cmd2消耗的输出快:缓冲区通常已满(或接近缓冲区),并且cmd1在尝试写入时经常阻塞,这会减慢其匹配速度cmd2的速度。 cmd2之所以能够全速运行,是因为缓冲区中始终有可用的输入,因此几乎不需要阻塞读取。
  • cmd2消耗的输入速度比cmd1产生输入的速度快:缓冲区通常为空(或接近缓冲区),并且cmd2在尝试读取时经常阻塞,这将其减慢到匹配cmd1的速度。 cmd1之所以能够全速运行,是因为始终有足够的空间可写入缓冲区,因此它几乎不必阻塞写入。