【问题标题】:File I/O slowing down my C loop文件 I/O 减慢了我的 C 循环
【发布时间】:2017-01-16 16:52:10
【问题描述】:

我有一个 C 程序,它在一个循环中执行“填充”,其中每次迭代都被计时到一些赫兹。这个循环过去能够以大约 80k hz 运行。

然后我在循环中添加了一些文件 I/O(读取/写入 linux 文件描述符),现在看来我无法打破 ~6k 循环/秒。操作本身非常便宜,所以我怀疑是某种内核上下文切换导致了一堆延迟。所以,两个问题:

  • 如何检查是否是这种情况?
  • 除了对我的内核进行 RT 修补外,我能做些什么吗?

【问题讨论】:

  • 你能给我们一个最简单的程序来演示这个问题吗? (包括你是如何计时的)
  • 你不能依赖不定时循环的时间。您需要在其中加入某种计时硬件。当然,I/O 会减慢任何流量。没有“便宜”的文件 IO。
  • 每秒尝试 80k 小文件 IO 可能不是最好的方法。仅当缓冲区足够大时,您不能将其全部打印到缓冲区并刷新到磁盘吗?或者,您可以使用 RAM 磁盘。
  • 某种内核上下文切换”?写入文件是system call。每秒 6k 系统调用听起来不太寒碜……
  • 磁盘 IO 慢。这就是发明缓冲和内存文件系统的原因。这两种经典方法之一是否与您的用例相关?

标签: c linux file


【解决方案1】:

不写入磁盘,而是写入 tmpfile()。看看性能是否有所提高。在一个体面的实现中,它应该被保存在内存中,直到它变得非常大。 如果这样可以解决您的问题,那么写入延迟会减慢您的速度。如果您一次性刷新整个 tmpfile,您可能会看到一些改进。将缓冲区设置为一个巨大的值将具有相同的效果。

【讨论】:

    【解决方案2】:

    我将回答我自己的问题,因为有一个非常直接的解决方案,只需要很少的代码修改。

    如果我们执行大量文件描述符读取/写入会减慢我们的程序,我们可以考虑使用mmap() 将文件描述符直接映射到内存,然后基本上将文件视为字节数组。只需确保分配足够的内存以适应您想要写入的任何内容。

    【讨论】:

    • 如果我们做大量的文件描述符读/写会减慢我们的程序,我们可以考虑使用 mmap() 将文件描述符直接映射到内存,然后基本上将文件视为一个字节数组。只需确保分配足够的内存以适应您要写入的任何内容。 这将不会解决从磁盘读取数据的问题 - 事实上,mmap 可能比一个简单的read() - 设置允许您“将文件视为字节数组”的虚拟映射是一个非常昂贵的操作。它可能工作 - 但只有如果您继续引用已读取的数据。
    • this comment from one Linus Torvalds(你可能听说过他...):“人们喜欢使用 mmap() 和其他方式来玩弄页表以优化复制操作,有时它是值得。但是,使用虚拟内存映射玩游戏本身就非常昂贵。它有许多人们倾向于忽略的非常实际的缺点......相当明显的设置和拆卸成本......页面错误很昂贵。就是这样映射被填充,而且速度很慢。"
    • 这里的重点是优化循环内的读/写 - 循环外的设置成本是可以的。
    • mmap() 映射是在访问页面时按需创建的。它们不是在调用 mmap() 时创建的。因此,您必须访问文件中的每个页面才能创建整个映射。这与将整个文件读入进程内存所需的 IO 数量完全相同。如果文件太大而无法放入内存,其中一些页面将被取消映射并且必须从磁盘重新读取。 mmap() 不会让您的 IO 问题消失。如果文件适合内存,您可以直接读取它。如果不合适,mmap() 将重做与读取文件相同的 IO 操作。
    • 这很有教育意义——你是说如果我正在读取的文件不是很大(这里是真的),那么 read() 并不是特别慢,因为内核会缓冲数据的方式与 mmap() 大致相同...?
    猜你喜欢
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多