当文件系统无法跟上bash重定向的输出时会发生什么?

时间:2013-10-29 20:11:05

标签: bash pipe

假设我有一些生成输出的进程my_proc。我在bash中使用>将该输出重定向到文件,如下所示:

./my_proc > /some/file

当文件系统无法跟上my_proc的输出时(即my_proc生成输出的速度比写入磁盘的速度快)会发生什么?我假设文件系统会做一些缓冲,但如果它永远不会赶上呢?

有没有办法配置最大缓冲区大小?

对我来说,最佳解决方案是在缓冲区溢出时开始丢弃输出(开始重定向到/dev/null或其他东西)。用bash有一个简单的方法吗?

3 个答案:

答案 0 :(得分:4)

只要文件系统赶上,您的应用程序写入调用就会被延迟。最有可能的净影响是你的应用程序在文件系统上运行较慢。

写入调用通常由OS IO子系统缓冲,除非使用适当的标志打开目标文件。但这不是stdout的情况。可以使用适当的选项安装文件系统以禁用缓冲(即同步模式),这样可以避免缓冲,但这通常不是出于性能原因而做的。

要获得您想要的内容,您需要将应用程序编程为缓冲输出并丢弃缓冲区,如果它检测到文件系统正在减慢您的速度。但这没有任何意义。如果您需要输出,那么您需要等待。如果你不需要它,那么最好不要在第一时间写它。

答案 1 :(得分:4)

我认为@ akostadinov的回答正确。这可以通过一个简单的例子轻松说明:

$ time seq 1 1000000
1
2
...
999999
1e+06

real    0m40.817s
user    0m0.600s
sys     0m0.510s
$ time seq 1 1000000 > file.txt

real    0m0.556s
user    0m0.540s
sys     0m0.020s
$ time seq 1 1000000 > /dev/null

real    0m0.546s
user    0m0.540s
sys     0m0.000s
$

我们使用seq实用程序输出数字1到1000000,并将输出重定向到不同的地方:

  • 没有重定向(输出到stdout / terminal),seq运行速度慢很多
  • 重定向到/ dev / null和一个真实文件非常接近,但是对于/ dev / null版本来说,显式时间的“sys”组件为零。

答案 2 :(得分:2)

在bash中没有简单的方法可以做到这一点,但你可以用C语言做到这一点。但首先,也许你可以通过编写每N行来逃脱?要仅将每100行写入文件,您可以执行以下操作:

slowprogram | sed -n '1~100p' > file

无论如何,让我们使用C片段进行真正的非阻塞。因为在缓冲但不是真的这样的行为,我们可以很有趣并称之为bluffer.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFFER_SIZE 4096

int main(int argc, char** argv) {
  int out;
  char buffer[BUFFER_SIZE];
  int c;

  out = open("/dev/stdout", O_NONBLOCK | O_APPEND | O_WRONLY);

  while((c = read(0, buffer, BUFFER_SIZE)) != 0) {
      write(out, buffer, c);
  }
}

现在考虑一个快速生成一百万行(~6.8MB)数据的命令:

time printf "%s\n" {1..1000000} > /dev/null

real    0m1.278s

现在让我们通过使用pv将速率限制为1MB / s来模拟慢速IO:

time printf "%s\n" {1..1000000} | pv -q -L 1M > slowfile

real    0m7.514s

正如所料,它需要更长的时间,但slowfile包含所有1,000,000行。

现在让我们插入我们的诈唬:

time printf "%s\n" {1..1000000} | ./bluffer | pv -q -L 1M > fastfile

real    0m1.972s

这一次它很快就完成了,fastfile只包含了1,000,000行中的141,960行。在文件中,我们看到这样的差距:

52076
52077
188042
188043