假设我有一些生成输出的进程my_proc
。我在bash中使用>
将该输出重定向到文件,如下所示:
./my_proc > /some/file
当文件系统无法跟上my_proc
的输出时(即my_proc
生成输出的速度比写入磁盘的速度快)会发生什么?我假设文件系统会做一些缓冲,但如果它永远不会赶上呢?
有没有办法配置最大缓冲区大小?
对我来说,最佳解决方案是在缓冲区溢出时开始丢弃输出(开始重定向到/dev/null
或其他东西)。用bash有一个简单的方法吗?
答案 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,并将输出重定向到不同的地方:
seq
运行速度慢很多答案 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