何时为I / O(C ++)构建自己的缓冲系统?

时间:2008-11-06 09:52:46

标签: c++ linux performance io buffer

我必须处理非常大的文本文件(2 GB),必须逐行读/写它们。使用ofstream编写2300万行非常慢,所以在开始时,我试图加快在内存缓冲区(例如256 MB或512 MB)中写入大块行的过程,然后将缓冲区写入文件。这不起作用,性能或多或少相同。我在阅读文件时遇到同样的问题。我知道I / O操作是由STL I / O系统缓冲的,这也取决于磁盘调度程序策略(由操作系统管理,在我的情况下是Linux)。

关于如何提高性能的任何想法?

PS:我一直在考虑使用后台子进程(或线程)来读取/写入数据块,而程序正在处理数据但我不知道(主要是在子进程的情况下)是否会值得。

7 个答案:

答案 0 :(得分:10)

2GB文件非常大,您需要了解可能成为瓶颈的所有可能区域:

  • 硬盘本身
  • HDD接口(IDE / SATA / RAID / USB?)
  • 操作系统/文件系统
  • C / C ++ Library
  • 您的代码

我首先做一些测量:

  • 您的代码读取/写入2GB文件需要多长时间,
  • dd”命令读取和写入磁盘的速度有多快?实施例...

    dd if=/dev/zero bs=1024 count=2000000 of=file_2GB

  • 使用大的fwrite()/ fread()调用写/读需要多长时间

假设您的磁盘能够以大约40Mb / s的速度进行读/写(这可能是一个真实的数字),您的2GB文件运行速度不会超过50秒。

实际上需要多长时间?

  

嗨Roddy,使用fstream读取方法   1.1 GB文件和大文件   它需要缓冲区(128,255或512 MB)   大约43-48秒,它是相同的   使用fstream getline(逐行)。   cp需要将近2分钟的时间来复制   文件。

在这种情况下,您的硬件绑定。 cp 必须读写,并且会在疯狂的时候在磁盘表面上来回搜索。因此,(如你所见)它将比简单的'读'案例差两倍多。

为了提高速度,我首先尝试的是更快的硬盘驱动器或SSD。

您还没有说过磁盘接口是什么? SATA几乎是最简单/最快的选择。另外(显而易见的是,这......)确保磁盘在运行代码的同一台机器上运行,否则你就是网络绑定......

答案 1 :(得分:8)

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

答案 2 :(得分:5)

也许您应该查看内存映射文件。

在此库中查看它们:Boost.Interprocess

答案 3 :(得分:3)

只是想一想,但是避免使用std :: endl,因为这会在缓冲区满之前强制刷新。使用'\ n'代替换行符。

答案 4 :(得分:2)

不要使用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);

另请阅读using underscore in identifier names:上的文章。请注意,您的代码可以,但是。

答案 5 :(得分:1)

使用getline()可能效率很低,因为当从流缓冲区向数据附加数据时,字符串缓冲区可能需要重新调整大小几次。您可以通过预先调整字符串大小来提高效率:

此外,您可以将iostreams缓冲区的大小设置为非常大或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.
}

答案 6 :(得分:0)

如果你要自己缓冲文件,那么我建议使用无缓冲的I / O进行一些测试(在你已经开启的文件上使用setvbuf可以关闭库缓冲)。

基本上,如果你要缓冲自己,你想要禁用库的缓冲,因为它只会让你感到痛苦。我不知道是否有任何方法可以为STL I / O做到这一点,所以我建议你去C级I / O.