我正试图将大量的数据写入我的SSD(固态硬盘)。我说的巨大是指80GB。
我在网上寻找解决方案,但我想到的最好的办法是:
#include <fstream>
const unsigned long long size = 64ULL*1024ULL*1024ULL;
unsigned long long a[size];
int main()
{
std::fstream myfile;
myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
//Here would be some error handling
for(int i = 0; i < 32; ++i){
//Some calculations to fill a[]
myfile.write((char*)&a,size*sizeof(unsigned long long));
}
myfile.close();
}
使用Visual Studio 2010编译,完全优化,在Windows7下运行,该程序最大可达20MB/s左右。真正困扰我的是,Windows可以以150MB/s到200MB/s之间的速度将文件从另一个SSD复制到这个SSD。至少快7倍。这就是为什么我认为我应该能跑得更快。
有什么办法可以加快我的写作速度吗?
fstreams本身并不比C流慢,但是它们使用更多的CPU(特别是在没有正确配置缓冲的情况下)。当CPU饱和时,会限制I/O速率。
至少MSVC 2015实现在没有设置流缓冲区时一次复制1个字符到输出缓冲区(参见streambuf::xsputn)。所以一定要设置一个流缓冲区(>0)。
使用以下代码,我可以用fstream获得1500MB/s的写入速度(我的M.2 SSD的全速):
#include <iostream>
#include <fstream>
#include <chrono>
#include <memory>
#include <stdio.h>
#ifdef __linux__
#include <unistd.h>
#endif
using namespace std;
using namespace std::chrono;
const size_t sz = 512 * 1024 * 1024;
const int numiter = 20;
const size_t bufsize = 1024 * 1024;
int main(int argc, char**argv)
{
unique_ptr<char[]> data(new char[sz]);
unique_ptr<char[]> buf(new char[bufsize]);
for (size_t p = 0; p < sz; p += 16) {
memcpy(&data[p], "BINARY.DATA.....", 16);
}
unlink("file.binary");
int64_t total = 0;
if (argc < 2 || strcmp(argv[1], "fopen") != 0) {
cout << "fstream mode\n";
ofstream myfile("file.binary", ios::out | ios::binary);
if (!myfile) {
cerr << "open failed\n"; return 1;
}
myfile.rdbuf()->pubsetbuf(buf.get(), bufsize); // IMPORTANT
for (int i = 0; i < numiter; ++i) {
auto tm1 = high_resolution_clock::now();
myfile.write(data.get(), sz);
if (!myfile)
cerr << "write failed\n";
auto tm = (duration_cast<milliseconds>(high_resolution_clock::now() - tm1).count());
cout << tm << " ms\n";
total += tm;
}
myfile.close();
}
else {
cout << "fopen mode\n";
FILE* pFile = fopen("file.binary", "wb");
if (!pFile) {
cerr << "open failed\n"; return 1;
}
setvbuf(pFile, buf.get(), _IOFBF, bufsize); // NOT important
auto tm1 = high_resolution_clock::now();
for (int i = 0; i < numiter; ++i) {
auto tm1 = high_resolution_clock::now();
if (fwrite(data.get(), sz, 1, pFile) != 1)
cerr << "write failed\n";
auto tm = (duration_cast<milliseconds>(high_resolution_clock::now() - tm1).count());
cout << tm << " ms\n";
total += tm;
}
fclose(pFile);
auto tm2 = high_resolution_clock::now();
}
cout << "Total: " << total << " ms, " << (sz*numiter * 1000 / (1024.0 * 1024 * total)) << " MB/s\n";
}
我在其他平台(Ubuntu, FreeBSD)上尝试了这段代码,没有注意到I/O率的差异,但CPU使用率的差异约为8:1 (fstream使用了8倍多的CPU)。所以可以想象,如果我有一个更快的磁盘,fstream写速度会比stdio版本慢。