Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将标准输出记录到文件的长延迟中断_C_Performance - Fatal编程技术网

C 将标准输出记录到文件的长延迟中断

C 将标准输出记录到文件的长延迟中断,c,performance,C,Performance,我有一个C程序,每10毫秒将数据写入标准输出3行。如果我将输出重定向到一个文件(使用>),程序的运行将有很长的延迟(60毫秒)。延迟是周期性的(比如每5秒一次) 如果我只是让它写入控制台或重定向到/dev/null,就没有问题了 我怀疑这是stdout缓冲区的问题,但是使用fflush(stdout)并没有解决问题 如何解决此问题?可能只是每5秒您就要填满磁盘缓冲区,而由于刷新到实际磁盘,延迟会出现峰值。请使用iostat检查您需要使用fsync。以下是: $ time ./fdatasync

我有一个C程序,每10毫秒将数据写入标准输出3行。如果我将输出重定向到一个文件(使用>),程序的运行将有很长的延迟(60毫秒)。延迟是周期性的(比如每5秒一次)

如果我只是让它写入控制台或重定向到/dev/null,就没有问题了

我怀疑这是stdout缓冲区的问题,但是使用fflush(stdout)并没有解决问题


如何解决此问题?

可能只是每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而优化的内核。但如果是问题,怎么办这可能是解决方案吗?我是否要创建另一个进程/线程并将这些输出输入其中?