假设我有一些my_proc
生成输出的过程。我>
在 bash 中使用将该输出重定向到一个文件,如下所示:
./my_proc > /some/file
当文件系统跟不上来自my_proc
(即my_proc
生成输出的速度快于写入磁盘的速度)?我假设文件系统会做一些缓冲,但如果它永远赶不上怎么办?
有没有办法配置最大缓冲区大小?
对我来说,最佳解决方案是在缓冲区溢出时开始丢弃输出(开始重定向到/dev/null
或其他东西)。有没有一种简单的方法可以用 bash 做到这一点?
只要文件系统赶上,您的应用程序写入调用就会延迟。最有可能的净效应是您的应用程序在文件系统上等待时运行速度变慢。
写入调用通常由 OS IO 子系统缓冲,除非使用适当的标志打开目标文件。但标准输出并非如此。可以使用适当的选项安装文件系统以禁用缓冲(即同步模式),这样可以避免缓冲,但出于性能原因通常不会这样做。
为了得到你想要的,你需要对你的应用程序进行编程以缓冲输出并在它检测到文件系统减慢你的速度时丢弃缓冲区。但这没有任何意义。如果需要输出,则需要等待。如果你不需要它,那么最好不要一开始就写它。
我认为@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
运行速度慢很多倍在 bash 中没有简单的方法可以做到这一点,但你可以在 C 中做到这一点。但首先,也许你可以只写每 N 行就行了?要仅将每 100 行写入文件,您可以执行以下操作:
slowprogram | sed -n '1~100p' > file
无论如何,让我们使用 C 代码片段实现真正的非阻塞。由于 at 的作用类似于缓冲区但实际上并非如此,因此我们可以很有趣地称之为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
现在让我们通过将其速率限制为 1MB/s 来模拟慢速 IO pv
:
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