我有一个用C ++实现的跨平台工具,它将大型二进制文件写入输出目录。我在整个代码中使用Boost和C ++ 11。此问题仅涉及Windows上的行为。
写入本地磁盘时,C ++ fstream.write
API的性能与WinAPI WriteFile
的性能相同。但是,当通过本地网络写入共享卷时,fstream
API的执行速度比WinAPI慢得多,速度要慢3到13倍。
我疯了吗?
以下是我所做的API调用(在循环中,写入4 MB的虚拟数据块)。我按顺序写作,所以没有必要进行搜索,但我列出了它的完整性:
C ++ fstream:
std::ofstream output(path, std::ios::binary | std::iostream::trunc);
output.seekp(offset);
output.write(data, size);
WinAPI的:
Handle handle = CreateFileW(path,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
TRUNCATE_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
SetFilePointer(handle, offset, NULL, FILE_BEGIN);
WriteFile(handle, data, size, &nwritten, NULL);
CloseHandle(handle);
我故意不在Windows Handle上设置任何“特殊”标志(例如顺序扫描,随机访问,无缓冲等)。
如果我希望用户使用NAS或其他网络卷,我是否应该期望在Windows上如此大的性能改进切换到WinAPI?显然我更喜欢使用C ++标准库,但在这种情况下它太慢了。
添加更多细节:
我的编译器是MSVC 2015 32位。
虚拟数据准备:
const int nsegments = 256;
const unsigned long segmentSizeMb = 4;
const unsigned long segmentSize = segmentSizeMb * 1024 * 1024;
std::vector<char> data(segmentSize);
for (long i = 0; i < segmentSize; i++) {
data[i] = static_cast<char>(i);
}
写循环:
for (int i = 0; i < nsegments; i++) {
// Call one of the following:
ofstream.write(data.data(), segmentSize);
// or
fwrite(data.data(), 1, segmentSize, fileptr);
// or
DWORD nwritten;
WriteFile(handle, data.data(), segmentSize, &nwritten, NULL);
}
我正在使用std::chrono
测量写入吞吐量,例如
auto start = std::chrono::steady_clock::now();
int nwrites = 0;
int nwritesPerReport = 8;
...
// (inside write loop):
if (++nwrites % nwritesPerReport == 0) {
auto now = std::chrono::steady_clock::now();
std::chrono::duration<double> duration = now - start;
double rate = nwrites * segmentSizeMb / duration.count();
// print rate, which has units MB/s
}
写入本地SSD时,我会观察到以下写入速率:
写入本地网络(WiFi,Windows PC)上共享的HDD时:
我认为在本地写入时观察到的狂野率与每种方法内部处理缓冲的方式有所不同。
通过网络写的观察率我不太确定。
我已尝试在fstream中禁用缓冲,并提供我自己的缓冲区,这两者都没有产生积极的影响:
ofstream.rdbuf()->pubsetbuf(NULL, 0);
// or
std::vector<char> buf(size);
ofstream.rdbuf()->pubsetbuf(buf.data(), size);
// where size ranges from 8KB to 1 MB
我还在同一本地网络上的不同计算机上的两个Linux VM上运行相同的测试:
Ubuntu 17.10 GCC 7.2.0(以太网):
CentOS 7 GCC 4.8.5(WiFi):