6

非常に大きなテキスト ファイル (2 GB) を処理する必要があるため、1 行ずつ読み書きする必要があります。ofstream を使用して 2,300 万行を書き込むのは非常に遅いため、最初は大量の行のチャンクをメモリ バッファー (たとえば 256 MB または 512 MB) に書き込み、そのバッファーをファイルに書き込むプロセスを高速化しようとしました。 . これは機能しませんでした。パフォーマンスはほぼ同じです。ファイルの読み取りに同じ問題があります。I/O 操作が STL I/O システムによってバッファリングされることはわかっています。これは、ディスク スケジューラ ポリシー (私の場合は Linux の OS によって管理される) にも依存します。

パフォーマンスを向上させる方法について何か考えはありますか?

PS: プログラムがデータを処理している間にバックグラウンドの子プロセス (またはスレッド) を使用してデータ チャンクを読み書きすることを考えていましたが、これが価値があるかどうかはわかりません (主にサブプロセスの場合)。

4

7 に答える 7

11

2GBのファイルはかなり大きいので、ボトルネックとして機能する可能性のあるすべての領域に注意する必要があります。

  • HDD自体
  • HDDインターフェース(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秒より速く実行することはできません。

実際にはどれくらい時間がかかりますか?

こんにちはロディ、1.1 GBのファイルと大きなバッファ(128、255、または512 MB)でfstream読み取り方式を使用すると、約43〜48秒かかります。これは、fstream getlineを使用しても同じです(行ごと)。cpはファイルをコピーするのにほぼ2分かかります。

その場合、あなたはハードウェアに縛られています。cpは読み取りと書き込みを行う必要があり、それを実行すると、狂ったようにディスク表面を前後にシークします。したがって、(ご覧のとおり)単純な「読み取り」の場合の2倍以上悪くなります。

速度を向上させるために、私が最初に試すのは、より高速なハードドライブまたは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);

識別子名でのアンダースコアの使用に関する記事もお読みください: 。あなたのコードはOKですが注意してください。

于 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を使用してテストすることをお勧めします(開いたファイルのsetvbufは、ライブラリのバッファリングをオフにすることができます)。

基本的に、自分でバッファリングする場合は、ライブラリのバッファリングを無効にする必要があります。これは、痛みを引き起こすだけだからです。STL I / Oでそれを行う方法があるかどうかわからないので、経営幹部レベルのI/Oに下げることをお勧めします。

于 2008-11-06T11:30:11.123 に答える