6

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

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

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

4

7 回答 7

11

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

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

我会先做一些测量:

  • 您的代码读取/写入 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 几乎是最简单/最快的选择。另外(很明显,这...)确保磁盘物理上位于您的代码正在运行的同一台机器上,否则您是网络绑定的...

于 2008-11-06T11:19:29.820 回答
8

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

于 2008-11-06T10:09:53.563 回答
5

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

在这个库中检查它们:Boost.Interprocess

于 2008-11-06T09:58:35.270 回答
3

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

于 2008-11-06T12:07:30.987 回答
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);

另请阅读有关在标识符名称中使用下划线的文章: . 请注意,您的代码可以,但是。

于 2008-11-06T12:42:56.267 回答
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.
}
于 2008-11-06T13:04:58.593 回答
0

如果您要自己缓冲文件,那么我建议您使用非缓冲 I/O 进行一些测试(在您打开的文件上设置 vbuf 可以关闭库缓冲)。

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

于 2008-11-06T11:30:11.123 回答