在生成数据时写入数据的最快方法

时间:2012-01-03 16:15:21

标签: c++ optimization file-io parallel-processing

在我的程序中,我正在模拟大量迭代的N体系统。对于每次迭代,我生成一组6N坐标,我需要将其附加到文件,然后用于执行下一次迭代。代码是用C ++编写的,目前使用ofstream的方法write()在每次迭代时以二进制格式写入数据。

我不是这个领域的专家,但我想改进这部分程序,因为我正在优化整个代码。我觉得与在每个周期写入计算结果相关的延迟会显着降低软件的性能。

我很困惑,因为我没有实际并行编程和低级文件I / O的经验。我想到了一些我想象的可以实现的抽象技术,因为我正在使用Unix操作系统编写现代(可能是多核)的机器:

  • 以n次迭代的方式在文件中编写数据(似乎有更好的方法可以继续...)
  • 使用OpenMP并行化代码(如何实际实现缓冲区以使线程正确同步,并且不重叠?)
  • 使用mmap(文件大小可能很大,按GB的顺序,这种方法是否足够强大?)

但是,我不知道如何最好地实施它们并将它们恰当地结合起来。

4 个答案:

答案 0 :(得分:3)

当然,在每次迭代时写入文件效率很低,很可能会降低计算速度。 (根据经验,取决于你的实际情况)

您必须使用producer -> consumer设计模式。它们将通过排队链接,如传送带。

  • 制作人将尝试尽​​可能快地制作,只有在消费者无法处理时才会减速。
  • 消费者会尽可能快地“消费”。

通过拆分两者,您可以更轻松地提高性能,因为每个过程都更简单,并且对另一个过程的干扰更少。

  • 如果制作人更快,你需要改善消费者,在你的情况下,以最有效的方式写入文件,大部分块(如你所说)
  • 如果消费者更快,你需要改进生产者,最有可能的是通过你说的并行化。

无需来优化两者。只优化最慢(瓶颈)。

实际上,您在它们之间使用线程和同步队列。有关实现提示,请查看here,尤其是§18.12“生产者 - 消费者模式”。

关于流量管理,您必须通过选择“最大队列大小”来增加一点复杂性,并在队列空间不足时让生产者等待。那么要小心死锁,仔细编码。 (参见我给出的维基百科链接)

注意:使用boost线程是个好主意,因为线程不是很便携。 (好吧,它们是从C ++ 0x开始,但C ++ 0x可用性还不好)

答案 1 :(得分:1)

最好将操作拆分为两个独立的流程:data-producingfile-writingData-producing将使用一些缓冲区进行迭代数据传递,file-writing将使用队列来存储写请求。然后,data-producing只发布一个写请求然后继续,而file-writing则会在后台处理写作。

基本上,如果数据生成的速度比可能存储的速度快得多,那么您很快就会将大部分数据保存在缓冲区中。在这种情况下,你的实际方法似乎是非常合理的,因为很少可以通过编程方式完成,然后改善情况。

答案 2 :(得分:1)

如果您不想在不同的线程中玩游戏,可以尝试使用允许异步写入的aio_write()。基本上你给操作系统写缓冲区,函数立即返回,并在程序继续时完成写操作,稍后你可以检查写操作是否完成。

这个解决方案仍然会遇到其他答案中提到的生产者/消费者问题,如果你的算法生成的数据比写入的速度快,最终你会耗尽内存来存储算法和写入之间的结果,所以你必须尝试一下,看看它是如何运作的。

答案 3 :(得分:0)

  

“使用mmap(文件大小可能很大,按GB的顺序,是这个   方法足够健壮?)“

mmap是操作系统加载程序,共享库和页面/交换文件的方法 - 它与任何其他文件I / O一样健壮,通常性能更高。

但是在大​​多数操作系统上,在使用映射文件时,扩展映射文件的大小是不好/困难/不可能的。因此,如果您知道数据的大小,或者您只是阅读,那就太棒了。对于你不断添加的日志/转储,它不太适合 - 除非你知道一些最大的大小。