C 将标准输出记录到文件的长延迟中断
我有一个C程序,每10毫秒将数据写入标准输出3行。如果我将输出重定向到一个文件(使用>),程序的运行将有很长的延迟(60毫秒)。延迟是周期性的(比如每5秒一次) 如果我只是让它写入控制台或重定向到/dev/null,就没有问题了 我怀疑这是stdout缓冲区的问题,但是使用fflush(stdout)并没有解决问题C 将标准输出记录到文件的长延迟中断,c,performance,C,Performance,我有一个C程序,每10毫秒将数据写入标准输出3行。如果我将输出重定向到一个文件(使用>),程序的运行将有很长的延迟(60毫秒)。延迟是周期性的(比如每5秒一次) 如果我只是让它写入控制台或重定向到/dev/null,就没有问题了 我怀疑这是stdout缓冲区的问题,但是使用fflush(stdout)并没有解决问题 如何解决此问题?可能只是每5秒您就要填满磁盘缓冲区,而由于刷新到实际磁盘,延迟会出现峰值。请使用iostat检查您需要使用fsync。以下是: $ time ./fdatasync
如何解决此问题?可能只是每5秒您就要填满磁盘缓冲区,而由于刷新到实际磁盘,延迟会出现峰值。请使用iostat检查您需要使用
fsync
。以下是:
$ time ./fdatasync
./fdatasync 0.00s user 0.01s system 1% cpu 0.913 total
fsync(文件号(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));
}
}
因此,它在0.913秒内运行fdatasync并将其同步到磁盘100次,平均每次写入和fdatasync调用约9ms
如果我将输出重定向到一个文件(使用>),将会有很长的时间
程序运行中的延迟(60毫秒)
这是因为当stdout
是一个终端设备时,它通常(尽管不是必需的)是行缓冲的,也就是说,当写入换行符时,输出缓冲区被刷新,而对于常规文件,输出缓冲区是完全的,这意味着缓冲区在满时或关闭文件时被刷新(当然,也可以显式调用fflush()
)
fflush(stdout)
对您来说可能不够,因为这只会刷新标准I/O库缓冲区,但内核也会缓冲并延迟写入磁盘。您可以在调用fflush()
后,在文件描述符上调用fsync()
,将修改后的缓冲区缓存页刷新到磁盘,如fsync(stdout\u FILENO)
请小心,在未调用fflush()
之前,不要调用fsync()
更新:您也可以尝试
sync()
,与fsync()
不同,它不会阻止等待底层写入返回。或者,正如另一个答案中所建议的那样,fdatasync()
可能是一个不错的选择,因为它避免了更新文件时间的开销。我测试了fsync,但它使问题变得更糟,现在每秒延迟20次。fsync似乎延迟很长。@Masood\u mj查看我的编辑-如果您想获得更好的性能,您必须使用fdatasync并提前知道写操作。实时性能sk I/O是一个挑战。@Masood_mj哼哼,可能是因为fsync()
在写入所有内容之前都会阻塞。请尝试sync()
(请参阅更新的答案)。因为它是用来记录日志的,我可以使用非阻塞文件吗?linux不是一个实时操作系统,延迟是不可避免的,尤其是在写入磁盘时。@user3386109,当然,但我想避免这种记录延迟。我已经将CPU内核与内核屏蔽,并将进程固定在内核上。我现在的问题是,当我建议est使用共享内存将输出传输到运行在不同内核上的进程,并让该进程将其写入磁盘。对我来说9毫秒还是太多了。如果我的进程每10毫秒等待9毫秒,这意味着它几乎没有时间做任何其他事情。@Masood_mj这是一个一般性的答案。大多数磁盘通常都没有优化对于短时间内的大量小写入,大多数文件系统也没有针对这一点进行优化。在另一个线程中调用fdatasync可能会更幸运,但除此之外,解决方案将是更好的硬件+高性能文件系统+专为高IOPS而优化的内核。但如果是问题,怎么办这可能是解决方案吗?我是否要创建另一个进程/线程并将这些输出输入其中?