如果我需要从分配的内存到磁盘写一个大文件,那么最有效的方法是什么?
目前我使用了以下内容:
char* data = static_cast<char*>(operator new(0xF00000000)); // 60 GB
// Do something to fill `data` with data
std::ofstream("output.raw", std::ios::binary).
write(data, 0xF00000000);
但我不确定最直接的方法是否也是最有效的,考虑到各种缓冲机制等。
我使用的是带有64位目标的Windows 7 64位和Visual Studio 2012 RC编译器。
答案 0 :(得分:2)
对于Windows,您应该使用CreateFile
API。仔细阅读该页面以及提及优化的任何链接。您传递了一些标志来关闭缓冲。我过去是这样做的,当时我以大约每秒800MB的速度收集视频,并且必须尽可能快地将其中的一小部分写入RAID阵列。
现在,对于旗帜 - 我认为主要是这些:
FILE_FLAG_NO_BUFFERING
FILE_FLAG_WRITE_THROUGH
对于阅读,您可能想要使用FILE_FLAG_SEQUENTIAL_SCAN
,但我认为如果关闭缓冲,则无效。
您需要做几件事。首先,您应该始终写入扇区大小倍数的数据量。这几乎是普遍存在(或至少是)512字节,但您可能希望将来考虑最多2048个字节。
其次,您的记忆也必须与该扇区大小对齐。您可以使用_aligned_malloc()
或仅分配超出需要的缓冲区并手动对齐。
可能存在其他内存优化问题,您可能希望将单个写入操作限制为内存页面大小。我从来没有深入到那个深度。我仍然能够以非常接近磁盘限制的速度写入数据。它比使用stdio调用快得多。
如果你需要在后台执行此操作,可以使用重叠的I / O,但说实话我从来不理解它。我创建了一个后台工作线程专门写出视频缓冲区并在外部控制它。
答案 1 :(得分:1)
最令人担忧的是输出文件的内存映射。根据数据的填充方式,您甚至可以通过指针将现有程序直接写入磁盘,最后不需要单独的写入步骤。它相信操作系统可以有效地分页文件,无论如何它可能与堆内存有关......可能会避免磁盘到磁盘的复制。
我不确定如何在Windows中专门执行此操作,但您可以通知操作系统您想要的内存访问模式以进一步提高性能。
(boost :: asio具有对内存映射文件的可移植支持)
答案 2 :(得分:1)
如果您想使用std::ofstream
,请确保以下内容:
out.setbuf(0, 0)
。std::locale
不进行任何字符转换,即std::use_facet<std::codecvt<char, char> >(loc).always_noconv()
产生true
。 "C"
语言环境就是这样做的。有了这个,我希望std::ofstream
与编写大缓冲区的任何其他方法一样快。我还希望它比使用内存映射I / O慢,因为内存映射I / O应该避免在读取内存时分页内存只是为了编写内容。
答案 3 :(得分:1)
使用CreateFile
打开文件,使用SetEndOfFile
预分配文件的空间(以避免在写入时出现太多碎片),然后使用2 MB大小的缓冲区调用WriteFile
(这个大小在大多数场景中效果最好)在循环中直到你把整个文件写出来。
FILE_FLAG_NO_BUFFERING
在某些情况下可能会有所帮助,并且可能会使其他情况变得更糟,因此不需要使用它,因为通常Windows文件系统写缓存正在很好地运行。