今天无意中翻到去年一个项目中做的测试和试验,发现自己都快忘记了,还是记下来备忘吧。
我早说过,Windows是一个能出专家,也需要专家的平台,因为有太多的东西它在文档里不告诉你,或者告诉你的不是实情,需要你去摸索。那些摸索了又用小本本记下来的,或者拾到别人小本本的,就是专家。
在我用过的其它平台,UNIX/Linux/MacOS当然都用不着这么麻烦,你随便遍个C/C++程序写文件,不需要你自己做什么特别的优化,它的性能就非常好。但是,Windows不行,Windows下只有专家才知道怎么办。
可是这个项目必须在Windows下面,并且需要长时间(至少20分钟,超过1小时也正常)、稳定、快速的记录数据,在任何一秒都不能低于120MBps。
呵呵,这是文档上找不着的,我们也来做回专家吧。
三个要点:
1.使用VirtualAlloc分配要写出数据使用的缓冲区
2.预先分配文件的磁盘空间
3.使用不带缓冲的文件读写操作
代码片断:
// 3...使用不带缓冲的文件读写操作
HANDLE hFileWrite = CreateFile(path, // name of the write
GENERIC_WRITE, // open for writing
0, // do not share
NULL, // default security
CREATE_ALWAYS, // overwrite existing
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, // normal file & no buffering
NULL); // no attr. template
// 2...预先分配文件的磁盘空间
int64_t sz = file_size;
SetFilePointer(hFileWrite, (long)sz, ((long*)&sz) + 1, FILE_BEGIN);
SetEndOfFile(hFileWrite); // 会分配文件的存储空间
SetFilePointer(hFileWrite, 0, NULL, FILE_BEGIN);
// 1...使用VirtualAlloc分配要写出数据使用的缓冲区
void *lpvBase = VirtualAlloc(
NULL, // system selects address
block_size, // size of allocation
MEM_RESERVE | MEM_COMMIT, // allocate reserved pages
PAGE_READWRITE); // protection = read/write
if ( lpvBase == NULL ) {
DWORD err = GetLastError();
throw err;
}
char *buffer = (char*)lpvBase;
for ( int i = 0; i < block_size; ++i)
buffer[i] = i;
// 4...写入本身很简单
WriteFile(hFileWrite, buffer, block_size, &nWrite, NULL);
// 5...记得清理
VirtualFree(
lpvBase, // base address of block
0, // bytes of committed pages
MEM_RELEASE); // decommit the pages
CloseHandle(fh);
其中,起决定性作用的是“1.使用VirtualAlloc分配要写出数据使用的缓冲区”。
在我的测试环境中(硬盘ST3320620AS,格式化为NTFS文件系统,默认分配单位大小),写入文件的速度3项全做时,平均文件写入速度(文件大小8G,写入块大小32M)为66MBps,甚至超过了我们测试用的专门磁盘工具在这个磁盘上的性能;只做第一项,然后直接用C++的ofstream::write()写出时(文件和块大小不变),平均速度为60MBps。
三项优化都不做时,不论用什么办法写,平均速度最多30MBps。