English 中文(简体)
何时为I/O构建自己的缓冲系统(C++)?
原标题:
  • 时间:2008-11-06 09:52:45
  •  标签:

我必须处理非常大的文本文件(2 GB),必须逐行读/写。使用 ofstream 写入 2300 万行非常缓慢,因此一开始我尝试通过在内存缓冲区中写入大块行(例如 256 MB 或 512 MB),然后将缓冲区写入文件来加快进程。这并没有奏效,性能差不多。我在读取文件时也遇到了同样的问题。我知道 STL I/O 系统对 I/O 操作进行了缓冲,并且这也取决于磁盘调度程序策略(由操作系统管理,在我的情况下是 Linux)。

如何提高表现有什么想法吗?

PS:我一直在考虑在程序处理数据时使用一个背景子进程(或线程)来读/写数据块,但我不确定(特别是在子进程的情况下)这是否值得。

最佳回答

一个2GB的文件非常大,你需要注意所有可能成为瓶颈的区域:

  • The HDD itself
  • The HDD interface (IDE/SATA/RAID/USB?)
  • Operating system/filesystem
  • C/C++ Library
  • Your code

我会先进行一些测量:

  • How long does your code take to read/write a 2GB file,
  • “dd” 命令可以读写磁盘的速度有多快?例如...

    dd if=/dev/zero bs=1024 count=2000000 of=file_2GB的中文翻译为:dd if=/dev/zero bs=1024 count=2000000 of=file_2GB

  • How long does it take to write/read using just big fwrite()/fread() calls

假设您的磁盘能够以大约40Mb / s的速度读/写(这可能是一个合理的起点),那么您的2GB文件运行速度不会超过约50秒。

它实际上需要多长时间? (Tā shíjì shàng xūyào duō cháng shíjiān?)

Hi Roddy, using fstream read method with 1.1 GB files and large buffers(128,255 or 512 MB) it takes about 43-48 seconds and it is the same using fstream getline (line by line). cp takes almost 2 minutes to copy the file.

在这种情况下,您的资源受硬件限制。 cp 必须读写,并且在执行此操作时将来回搜索磁盘表面,导致性能类似于简单的读取情况的两倍以上(如您所见)。

为了提高速度,我会首先尝试使用更快的硬盘,或者固态硬盘。

你还没有说硬盘接口是什么?SATA基本上是最简单/最快的选项。另外(这很明显……)确保硬盘物理上与运行您的代码的同一台机器在一起,否则您就会受到网络的限制。

问题回答

我还建议使用内存映射文件,但如果你要使用 boost,我认为 boost::iostreams::mapped_file 比 boost::interprocess 更匹配。

也许你应该研究一下内存映射文件。

请在这个图书馆中检查它们:Boost.Interprocess

Just a thought, but avoid using std::endl as this will force a flush before the buffer is full. Use instead for a newline.

不要使用new分配缓冲区。

尝试:std::vector<>

unsigned int      buffer_size = 64 * 1024 * 1024; // 64 MB for instance.
std::vector<char> data_buffer(buffer_size);
_file->read(&data_buffer[0], buffer_size);

也请阅读关于在标识符名称中使用下划线的文章。请注意您的代码无问题,但…。

使用getline()可能效率低下,因为随着从流缓冲区附加到字符串缓冲区中的数据的增加,字符串缓冲区可能需要被多次重新调整大小。通过预先调整字符串的大小,可以使其更加高效。

您还可以将iostream缓冲区的大小设置为非常大或NULL(对于非缓冲)

// Unbuffered Accesses:
fstream file;
file.rdbuf()->pubsetbuf(NULL,0);
file.open("PLOP");

// Larger Buffer
std::vector<char>  buffer(64 * 1024 * 1024);
fstream            file;
file.rdbuf()->pubsetbuf(&buffer[0],buffer.size());
file.open("PLOP");

std::string   line;
line.reserve(64 * 1024 * 1024);

while(getline(file,line))
{
    // Do Stuff.
}

如果你打算自己进行缓冲文件,则建议使用非缓冲I/O进行测试(使用setvbuf将已fopen的文件关闭库缓冲)。

基本上,如果你要缓冲自己,你想要禁用库的缓冲,因为它只会带来痛苦。我不知道是否有任何方法来处理STL I/O,因此我建议降级到C级别的I/O。





相关问题
热门标签