在 C++ 中通过块异步保存大型二进制文件的最佳方法
Posted
技术标签:
【中文标题】在 C++ 中通过块异步保存大型二进制文件的最佳方法【英文标题】:Best way to save a large binary file by chunks asynchronously in C++ 【发布时间】:2021-07-06 03:40:57 【问题描述】:我正在开发一个 C++ 应用程序,它的输出是一个大的二进制文件(几 GB,基本上是一个大的浮点序列)。该文件的内容是由并行进程异步生成的。
每次进程完成时,它的结果必须保存到磁盘中二进制文件内的相应位置(进程完成的顺序不一定与它们的结果存储在磁盘。大约需要 5 个进程才能获得输出的完整数据)。
在 C++ 中实现这一目标的最佳方法是什么?我有几个可行的解决方案,但也许可以在最小化磁盘使用方面进行改进:
为每个完成的进程保存单独的文件,然后合并 保持 fstream 打开并使用 seekp() 为每个保存操作定位 put 指针【问题讨论】:
几 GB 的文件?为什么不先将其存储在 RAM 中;一个大的std::vector<float>
。填好后,生成文件。
如果合并文件很简单,那么这可能就是要走的路。否则,您需要担心同步问题。
您是提前知道最终文件中的确切位置,还是在所有过程完成后确定它们?块是否与某个边界对齐?
提前知道最终文件中的确切位置,以及文件的最终大小
这是特定于操作系统和文件系统的。我的建议(如果在 Linux 上)是生成十几个较小的文件(例如每个 100Mbytes)或考虑使用 sqlite 或 PostGreSQL... 不要忘记备份输出(远程或在外部媒体上)
【参考方案1】:
如果可以避免的话,我不建议将时间浪费在写入临时文件和合并上。
序列化到单个进程/单个流可能会快得多。但请确保在至少 64 KB 的某些块中进行查找和写入,以减少开销。
我根本不会使用 fstream,因为它们会带来一些开销(并且您依赖于实现的质量,这在 1、2、3、4 中很明显)。最好只使用fopen
,禁用缓冲,然后写入 64 KB+ 的块。
为了获得更好的性能,可以使用内存映射 I/O,例如使用 Boost.iostreams (example)。您也可以从多个进程进行内存映射。
如果单独进程生成的片段是 4 KB 或更大的倍数,在大多数操作系统上,您可以简单地在每个进程中打开相同的文件,寻找所需的位置并写入(不是很便携,但在 Linux、BSD 上可以和 Win32)。在 Win32 上只需要相应地设置文件共享模式。
【讨论】:
以上是关于在 C++ 中通过块异步保存大型二进制文件的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章