我正在使用std::ofstream
向网络位置写入可能较大(多千兆字节)的二进制文件。以前我经常冲洗缓冲区,这会影响性能,特别是在高峰时段 - 降低冲洗频率有帮助。我有兴趣找到其他方法来进一步提高写入性能。
根据各种在线资源,直接通过streambuf
直接写入与流stream.rdbuf()->pubsetbuf(buffer)
对象关联的缓冲区,避免了here所描述的写入开销。
不是将每个值依次传递给ofstream::write
,而是填充并传递一个具有8192字节固定大小的字节缓冲区。我原本以为直接填充缓冲区会避免调用write
,但省略写入会导致没有写入文件。在任何情况下,我的测试表明使用pubsetbuf with write比使用pubsetbuf并且一次写一个8字节值要快得多。
不幸的是,如果我在每次写入调用后都没有刷新流,则缓冲区的内容都会附加到文件并在开始时写入,并覆盖先前在该位置的数据。如果flush
紧跟write
次呼叫,则生成的文件正确无误。我每次发生写操作时都检查过流指针是否正确。
或者,如果我根本不打扰调用stream.rdbuf()->pubsetbuf(buffer)
并继续将预先填充的字节缓冲区传递给write
,我就不需要刷新了。我目前正在分析这两种方法中哪一种表现更好:
这说明了覆盖率大大降低的问题(注释stream.flush()
重新使用,以使其正常运行):
vector<double> data;
for (int i = 0; i < 400; ++i) data.push_back(111.0);
for (int i = 0; i < 400; ++i) data.push_back(222.0);
for (int i = 0; i < 400; ++i) data.push_back(333.0);
bool lastPoint;
size_t numPoints = data.size();
size_t bytesPerValue = sizeof(data[0]);
// Create a byte buffer
static const size_t BUFFER_SIZE = 8192;
vector<unsigned char> buffer;
buffer.resize(BUFFER_SIZE);
size_t bufferIndex = 0;
bool bufferFull = false;
// Create output stream
ofstream stream("\\\\server\\networkpath\\output.dat", ios::binary);
// Set stream buffer to avoid write calls
stream.rdbuf()->pubsetbuf(reinterpret_cast<char*>(&buffer[0]), BUFFER_SIZE);
for (size_t i = 0; i < numPoints; i++)
{
lastPoint = i == (numPoints - 1);
// Write to buffer
memcpy(&buffer[bufferIndex], reinterpret_cast<const unsigned char*>(&data[i]), bytesPerValue);
// Find next empty index
bufferIndex += bytesPerValue;
bufferFull = ((bufferIndex + bytesPerValue) > BUFFER_SIZE);
if (lastPoint || bufferFull)
{
stream.write(reinterpret_cast<const char*>(&buffer[0]), bufferIndex);
//stream.flush();
// If the line above is commented back in, the content of the output file is correct.
// However, I wish to avoid flushing often when writing across network.
// Without commenting back in, the file contains the expected number of bytes (9600) but the data in the second write call
// (bytes 8193-9600) appears both at the start and end of the file.
bufferIndex = 0;
}
}
stream.flush();
stream.close();
有没有办法通过pubsetbuf使用缓冲技术,而不需要每次执行写入时刷新?