std :: ifstreamはFILEよりもかなり遅いですか?
-
20-08-2019 - |
質問
特定のファイル(テキストファイル、サイズ326 kb)の解析が30倍以上遅いため、ライブラリが本来よりも遅いことが通知されました。ユーザーは、(おそらくstd::ifstream
ではなく)FILE
を使用している可能性があることを示唆しました。
やみくもに書き直したくないので、ボトルネックは他の場所にあると思うので、最初にここで確認したいと思いました。文字ごとに読んでいるので、使用している関数はget()
、peek()
、およびtellg()/seekg()
のみです。
更新:
プロファイルを作成し、紛らわしいの出力を取得しました-gprofはそうは思わなかったようです長いです。最初にファイル全体をバッファに読み込むようにプログラムを書き直し、約100倍高速化しました。問題は長い時間がかかったifstream
だったのではないかと思いますが、gprofは何らかの理由でそれを見ることができなかったかもしれません。いずれの場合でも、<=>は、このサイズであってもファイル全体をバッファリングするようには見えません 。
解決
それが違いを生むとは思わない。特に文字ごとに読んでいる場合、I / Oのオーバーヘッドが他の何かを完全に支配する可能性があります。 なぜ一度に1バイトを読むのですか?どれほど効率が悪いかご存知ですか?
326kbファイルの場合、最も高速な解決策は一度にメモリに読み込むことです。
std :: ifstreamとCの同等物との違いは、基本的に1つまたは2つの仮想関数呼び出しです。 1秒間に数千万回実行すると違いが生じる場合があります。ファイルI / Oは一般に非常に遅いため、アクセスに使用されるAPIはそれほど重要ではありません。さらに重要なのは、読み取り/書き込みパターンです。シークの多くは不良で、シーケンシャルな読み取り/書き込みは良好です。
他のヒント
やや遅いはずですが、あなたが言ったように、それはボトルネックではないかもしれません。プログラムのプロファイルを作成して、それが当てはまるかどうかを確認してみませんか?
fstreamからFILE *に切り替えることで問題が解決される可能性は低いと思います。通常は両方ともCライブラリによってバッファされます。また、OSは読み取りをキャッシュできます(Linuxはその点で非常に優れています)。アクセスしているファイルのサイズを考えると、RAMに完全にある可能性が高いです。
PolyThinkerのように、プロファイラーを介してプログラムを実行し、問題の場所を特定することが最善策だと言います。
また、seekg / tellgを使用しているため、ディスクが大きく断片化されている場合、ディスクを初めて読み込むときにヘッドを正しい位置に移動する必要があるため、顕著な遅延が発生する可能性があります。
すべてのベンチマークは悪です。期待するデータのコードをプロファイルするだけです。
Ruby、Python、Perl、C ++の間でI / Oパフォーマンスの比較を1回実行しました。私のデータ、言語バージョンなどでは、C ++のバリアントは数倍遅くなりました(当時は大きな驚きでした)。
プロファイルを作成することに同意します。しかし、一度に1文字ずつファイルを読み取る場合は、メモリマップファイルを作成してみてはどうでしょうか。そうすれば、ファイルを文字の配列のように扱うことができ、OSがすべての低レベルのバッファリングを処理する必要があります。最も簡単で恐らく最速の解決策は私の本での勝利です。 :)
こちらは極端な条件下では、fstream
sが実際に非常に遅いことを示す優れたベンチマーク...
- バッファリングを使用します(十分に強調できません)
- 自分でバッファを操作します(つまり、リンクされた質問でOPなどのパフォーマンスが必要な場合)。これは
FILE*
を使用する場合とそれほど変わりません。
ただし、時期尚早に最適化するべきではありません。 fstreams
は一般的に優れており、将来的に最適化する必要がある場合は、後でほとんどコストをかけずにいつでも実行できます。最悪の事態に事前に備えるために、<=>の最小プロキシを今すぐ作成して、後で最適化できるようにすることをお勧めします。他に手を加える必要はありません。