I / O(C ++)用に独自のバッファシステムを構築する場合
-
06-07-2019 - |
質問
非常に大きなテキストファイル(2 GB)を処理する必要があります。1行ごとに読み書きする必要があります。 ofstreamを使用して2,300万行を書き込むのは非常に遅いので、最初は、メモリバッファー(たとえば256 MBまたは512 MB)に大きな行のチャンクを書き込むプロセスを高速化してから、バッファーをファイルに書き込みました。これは機能しませんでしたが、パフォーマンスはほぼ同じです。ファイルの読み取りと同じ問題があります。 I / O操作はSTL I / Oシステムによってバッファリングされ、これはディスクスケジューラポリシー(OS、私の場合はLinuxによって管理される)にも依存します。
パフォーマンスを改善する方法についてのアイデアはありますか
PS:プログラムがデータを処理している間にバックグラウンドの子プロセス(またはスレッド)を使用してデータチャンクを読み書きすることを考えていますが、これが(主にサブプロセスの場合)わからない価値がある。
解決
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秒より速く実行できません。
実際にかかる時間はどのくらいですか?
Hi Roddy、fstream読み取りメソッドを使用 1.1 GBファイルと大容量 バッファ(128,255または512 MB) 約43〜48秒で、同じです fstream getline(行ごと)を使用します。 cpのコピーには約2分かかります ファイル。
その場合、あなたはハードウェアに縛られています。 cp は読み取りと書き込みを行う必要があり、それを実行すると、狂ったようにディスク表面を行き来します。そのため、(ご覧のように)単純な「読み取り」の場合の2倍以上になります。
速度を向上させるために、私が最初に試みることは、より高速なハードドライブ、またはSSDです。
ディスクインターフェースとは何ですか? SATAは、ほとんどの最も簡単/最速のオプションです。また、(明らかな点、これは...)ディスクが物理的にコードが実行されているのと同じマシン上にあることを確認してください。そうでなければ、ネットワークにバインドされています...
他のヒント
メモリマップファイルもお勧めしますが、ブーストを使用する場合は、 boost :: iostreams :: mapped_file は、boost :: interprocessよりも優れた一致です。
メモリマップファイルを調べる必要があるかもしれません。
このライブラリでそれらを確認します: Boost.Interprocess
考えてみてください。ただし、std :: endlの使用は避けてください。バッファがいっぱいになる前にフラッシュが強制されるためです。改行には代わりに「\ n」を使用します。
そのようなバッファの割り当てにnewを使用しないでください:
試してください:std :: vector <!> lt; <!> gt;
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()の使用は、データがストリームバッファから追加されるときに文字列バッファのサイズを数回変更する必要があるため、効率が悪い場合があります。これをより効率的にするには、文字列のサイズを事前に設定します。
また、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.
}
ファイルを自分でバッファリングする場合は、バッファリングされていないI / Oを使用してテストすることをお勧めします(fopenしたファイルのsetvbufはライブラリのバッファリングをオフにすることができます)。
基本的に、自分でバッファリングする場合は、ライブラリのバッファリングを無効にする必要があります。これは痛みを引き起こすだけだからです。 STL I / Oでそれを行う方法があるかどうかはわかりませんので、CレベルのI / Oに移行することをお勧めします。