GB の大きさ (10 GB など) のファイルを読みたいと思います。そのようなファイルを C で読み取る最速の方法は何ですか。実装を試みていますが、tail
I/O がボトルネックになる可能性があると思います。どんな提案も歓迎します。
3 に答える
まず第一に、物理 IO が、使用されるキャッシュよりもはるかに大きなファイルに対して十分高速であり、CPU バウンド処理がボトルネックである汎用コンピューターをまだ見たことがありません。とはいえ、すべての汎用コンピューターが存在するのを見たわけではありません。
そのため、移植性、保守性、可読性などの他の要因に対して、CPU サイクルの最適化のバランスを取る必要があります。あなたによって与えられたものを含むほとんどのユースケースは、ランタイムライブラリ関数を単に使用することを強く指していると思います。それらの作成者は、自分が何をしているのかをよく知っていると信じています。
大きなファイルを処理するには、低レベルのread
システム コールを使用する必要があります。より一般的ではなく、オーバーヘッドも高くなりますfread
。(stdio.h
出力する必要がある比較的少量の出力に使用しても問題ありません。)
を使用lseek
してファイルの大部分をスキップし、チャンクで逆方向にスキャンして行の境界を見つけます。
mmap
このアプリケーションでは避けます。カーネルで役に立たない I/O ヒューリスティックを引き起こす可能性があり、必要のない移植性の頭痛の種が山ほど追加されます。
それだけでは不十分な場合は、行き詰まった特定の場所を新しい質問として投稿してください。
他の人が言ったように、すべての環境に一般的な答えはありません。あなたができる最善のことは、多くの代替案をベンチマークすることです。
ただし、得られる結果を説明する可能性のあることがいくつかあります。
計算と読み取り操作の重複: 最新のマシンには、以前に読み取ったバッファーを処理している間に、データをディスクから 1 つ以上のバッファーにストリーミングできるようにするダイレクト メモリ アクセス (DMA) ハードウェアとバス アーキテクチャがあります。アイデアは、すべてのデバイス インターフェイスとバスをフル キャパシティで動作させるために必要なだけ多くの並列ストリームを実行することです。さもなければ、CPU が処理で最大になる (そして、以下で説明するような無駄なコピーではない)、または - 完璧な世界では - 両方です。たとえば、Windows オーバーラップ IOを見てください。
バッファリング: ディスク I/O ハードウェアとドライバー、ファイル システム、カーネル/ユーザー空間の境界、言語 I/O API、および独自のアプリケーション コードはすべて、データをバッファーできる場所です。ある例では、テキスト I/O に標準の C ライブラリを使用しているときに、PC で 4 レベルのバッファリング/キャッシュを識別することができました。これにより、すべてのバイトが少なくとも 4 回コピーされることは避けられませんでした。教訓は、巨大なストリームに連続した順序で未加工の形式でアクセスしていることを知っている場合 (たとえば、\n を \r\n に置き換えない)、マシンが実行する必要があるのはアプリケーションだけであるということです。実行すると、バッファリングのこれらの層はほとんど役に立たなくなります。低レベルのインターフェイスを使用して排除できるほど、高速化できます。低レベルのWindows IO API少なくとも、すべてのユーザー空間のバッファリングとコピーを排除します。
ディスク チャネルのパフォーマンスと並列性: ファイルが複数のディスク (RAID など) にまたがって保存され、インターフェイスに個別の DMA チャネルがある場合、OS やコードは並列ハードウェアの利点を得ることができます。同様に、対価を支払うという点で、すべてのディスク インターフェイスが同等に作られているわけではありません。これは深いトピックですが、一般に、サーバーはディスクの並列処理と高スループットのために最適化されています。非常に大きなファイルを扱うアプリケーションは、平均的な PC よりもサーバー ハードウェアでより高速に実行される可能性が高く、非同期/オーバーラップ IO を悪用する機会が多くなります。