1

当系统 IO 忙但仍有大量 CPU 时,我有一个fprintf呼叫阻塞了大约 10 秒。我既没有setvbuf底层流也没有打开底层 fd O_DIRECT。这意味着流同时具有 stdio 流和系统缓存。

我不知道一个fprintf电话怎么会被阻止这么长时间。对于底层流的流缓冲区已满的最坏情况,我认为 libc 只是调用write(2)将缓冲区内容写入磁盘。但据我所知,write(2)在未打开的 fd 上O_DIRECT不会等待磁盘传输,即它对于磁盘 IO 是异步的。所以我能想到的唯一耗时的工作是内核为写入的数据分配缓存,但这似乎不是一个 10 秒的工作,即使系统内存不足。实际上,系统有几十 MB 的空闲内存和几 GB 的缓存内存。

有什么建议吗?

谢谢。

4

4 回答 4

0

你说你没有调用setvbuf()流,但是流使用了什么样的缓冲?除非您使用的流是stderr(或有时stdout),否则默认情况下它将被块缓冲,这意味着在缓冲区满(通常为 4096 字节或更多)之前不会发生写入。根据您编写日志的频率,这可能会导致您感知到的 10 秒延迟。

所以我会尝试:setvbuf(my_stream, NULL, _IONBF, 0);

编辑: ......或者,我可能完全误解了“被阻止”这个词。无论如何都要离开,以防万一。

于 2010-11-24T09:00:57.713 回答
0

您是否在不止一台机器上运行您的代码?如果是这样,行为是否相同?

如果没有,请检查系统日志中的磁盘访问错误,一旦我遇到类似问题并且原因是磁盘故障。

于 2010-11-24T07:59:11.227 回答
0

写调用不是异步的,即系统调用必须从内核返回。当然这个系统调用,主要是把数据放到一个 I/O 队列上,稍后再进行真正的传输。但是,我猜这个 I/O 队列可能会在相当长的一段时间内无法访问。

这与您正在写入的媒体无关,只要它是块设备即可。我有一个程序将 JPEG 图像流写入 SD 卡。由于在硬盘上进行操作,该程序会卡住。

但是,如果这是写调用阻塞十秒钟的问题,您可以尝试 strace 程序。我不知道它会如何或是否会干扰您尝试观察的行为

strace -T -e trace=write progname

如果您想监视您的日志活动,您可以将日志写入重定向到管道或命名管道,放置一个本质上从该管道读取并写入您的日志文件的进程,然后对其进行跟踪。

于 2010-11-24T08:54:56.457 回答
0

如果您的进程正在向磁盘写入大量数据,它将在页面缓存中创建许多脏页,并write()最终迫使您的进程对其中一些页面进行同步写回。在这种情况下,内核在将合理数量的数据写入磁盘之前不会返回到您的进程(不过,10 秒听起来还是有点高)。

于 2010-11-25T05:27:14.823 回答