我有一个C程序,每10ms写入3行到stdout。如果我将输出重定向到文件(使用>),程序的运行会有很长的延迟(60ms)。延迟是周期性的(比如说每5秒钟)。
如果我只是让它写入控制台或重定向到/ dev / null,则没有问题。
我怀疑这是stdout缓冲区问题,但使用fflush(stdout)并没有解决问题。
我该如何解决这个问题?
答案 0 :(得分:3)
您需要使用fsync
。以下内容:
fsync(fileno(stdout))
应该有所帮助。请注意,Linux内核仍将根据其内部调度程序限制缓冲限制I / O.如果你没有得到你想要的频率,那么以root身份运行并设置一个非常低的nice
值可能会有所不同。
如果仍然太慢,请尝试使用fdatasync
。每个fflush
和fsync
都会导致文件系统更新节点元数据(文件大小,访问时间等)以及实际数据本身。如果你知道你将要编写多少数据,那么你可以尝试以下技巧:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv){
FILE *fp = fopen("test.txt", "w");
char *line = "Test\n";
char *fill = "\0";
fwrite(fill, 1, 100*strlen(line), fp);
fflush(fp);
fsync(fileno(fp));
rewind(fp);
for (int i = 0; i < 100; i++){
fwrite(line, strlen(line), 1, fp);
fflush(fp);
fdatasync(fileno(fp));
}
}
第一个fwrite调用在一个块中将5 * 100个零写入文件,并使用fsyncs将其写入磁盘并更新节点信息。现在我们可以在文件中写入最多500个字节而不会丢弃文件系统元数据。 rewind(3)
将文件指针位置返回到文件的开头,这样我们就可以在不改变节点文件大小的情况下写入数据。
该计划的时间安排如下:
$ time ./fdatasync
./fdatasync 0.00s user 0.01s system 1% cpu 0.913 total
因此它在0.913秒内运行fdatasync并同步到磁盘100次,平均每次写入约9ms&amp; fdatasync call。
答案 1 :(得分:3)
如果我将输出重定向到文件(使用&gt;),则会很长 在程序运行中延迟(60ms)。
那是因为当stdout
是终端设备时,它通常(虽然不是必需的)行缓冲,也就是说,当写入换行符时刷新输出缓冲区,而在在常规文件的情况下,输出是完全缓冲的,这意味着缓冲区在它们已满或者你关闭文件时被刷新(或者你明确地调用fflush()
)。
fflush(stdout)
对您来说可能还不够,因为它只会刷新标准I / O库缓冲区,但内核也会缓冲并延迟写入磁盘。您可以在调用fsync()
后调用文件描述符上的fflush()
以将修改后的缓冲区缓存页刷新到磁盘,如fsync(STDOUT_FILENO)
中所示。
请小心,不要在不致电fsync()
的情况下致电fflush()
。
更新:您还可以尝试sync()
,与fsync()
不同,它不会阻止等待基础写入返回。或者,正如另一个答案中所建议的那样,fdatasync()
可能是一个不错的选择,因为它可以避免更新文件时间的开销。
答案 2 :(得分:1)
可能只是每隔5秒就会填满你的磁盘缓冲区,并且由于刷新到实际的磁盘而导致延迟出现峰值。使用iostat检查