今天無意中翻到去年一個項目中做的測試和試驗(yàn),發(fā)現(xiàn)自己都快忘記了,還是記下來備忘吧。
我早說過,Windows是一個能出專家,也需要專家的平臺,因?yàn)橛刑嗟臇|西它在文檔里不告訴你,或者告訴你的不是實(shí)情,需要你去摸索。那些摸索了又用小本本記下來的,或者拾到別人小本本的,就是專家。
在我用過的其它平臺,UNIX/Linux/MacOS當(dāng)然都用不著這么麻煩,你隨便遍個C/C++程序?qū)懳募?,不需要你自己做什么特別的優(yōu)化,它的性能就非常好。但是,Windows不行,Windows下只有專家才知道怎么辦。
可是這個項目必須在Windows下面,并且需要長時間(至少20分鐘,超過1小時也正常)、穩(wěn)定、快速的記錄數(shù)據(jù),在任何一秒都不能低于120MBps。
呵呵,這是文檔上找不著的,我們也來做回專家吧。
三個要點(diǎn):
1.使用VirtualAlloc分配要寫出數(shù)據(jù)使用的緩沖區(qū)
2.預(yù)先分配文件的磁盤空間
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...預(yù)先分配文件的磁盤空間
int64_t sz = file_size;
SetFilePointer(hFileWrite, (long)sz, ((long*)&sz) + 1, FILE_BEGIN);
SetEndOfFile(hFileWrite); // 會分配文件的存儲空間
SetFilePointer(hFileWrite, 0, NULL, FILE_BEGIN);
// 1...使用VirtualAlloc分配要寫出數(shù)據(jù)使用的緩沖區(qū)
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分配要寫出數(shù)據(jù)使用的緩沖區(qū)”。
在我的測試環(huán)境中(硬盤ST3320620AS,格式化為NTFS文件系統(tǒng),默認(rèn)分配單位大小),寫入文件的速度3項全做時,平均文件寫入速度(文件大小8G,寫入塊大小32M)為66MBps,甚至超過了我們測試用的專門磁盤工具在這個磁盤上的性能;只做第一項,然后直接用C++的ofstream::write()寫出時(文件和塊大小不變),平均速度為60MBps。
三項優(yōu)化都不做時,不論用什么辦法寫,平均速度最多30MBps。