23

これは純粋なプログラミングの質問ではありませんが、fseek()を使用するプログラムのパフォーマンスに影響を与えるため、それがどのように機能するかを知ることが重要です。閉じられないように少し免責事項。

ファイルの途中にデータを挿入するのがどれほど効率的か疑問に思います。1MBのデータを含むファイルがあり、512KBのオフセットで何かを挿入するとします。ファイルの最後にデータを追加する場合と比較して、どれくらい効率的ですか?例を完成させるために、16KBのデータを挿入するとします。

答えはファイルシステムによって異なることは理解していますが、一般的なファイルシステムで使用されている手法は非常に似ていると思います。正しい概念を理解したいだけです。

4

6 に答える 6

5

(免責事項:この興味深い議論にいくつかのヒントを追加したいだけです)私見:考慮すべき点がいくつかあります:

1) fseek は主要なシステム サービスではなく、ライブラリ関数です。そのパフォーマンスを評価するには、ファイル ストリーム ライブラリの実装方法を検討する必要があります。一般に、ファイル I/O ライブラリはユーザー空間にバッファリングのレイヤーを追加するため、ターゲット位置が現在のバッファーの内側または外側にある場合、fseek のパフォーマンスはまったく異なる場合があります。また、I/O ライブラリが使用するシステム サービスもさまざまです。つまり、一部のシステムでは、可能であれば、ライブラリがファイル メモリ マッピングを広範囲に使用します。

2)あなたが言ったように、異なるファイルシステムは非常に異なる方法で動作する場合があります。特に、トランザクショナル ファイルシステムは、ファイルの途中で中断された書き込み操作のロールバックの可能性に備えるために、非常にスマートでおそらくコストのかかることを行う必要があると思います。

3) 最新の OS には、非常に積極的なキャッシュ アルゴリズムがあります。「fseeked」ファイルはすでにキャッシュに存在する可能性が高いため、操作がはるかに高速になります。ただし、他のプロセスによって生成されるファイルシステム全体のアクティビティが重要になると、それらは大幅に低下する可能性があります。

コメントはありますか?

于 2010-03-13T16:23:15.420 に答える
4

例として、ext2 FS と Linux OS を想定します。挿入と追加の間に大きなパフォーマンスの違いがあるとは思いません。どちらの場合も、ファイル ノードとオフセット テーブルを読み取り、関連するディスク セクタをメモリにマップし、データを更新し、後でデータをディスクに書き戻す必要があります。この例で大きなパフォーマンスの違いを生むのは、ファイルの一部にアクセスするときの時間的および空間的な局所性です。これにより、ロード/ストアの組み合わせの数が減るためです。

以前の回答では、FS ブロック サイズの正確な倍数のデータ書き込みを処理する場合、両方の操作を高速化できる可能性があると述べています。FS ドライバーへの低レベルのアクセスが必要になるため、これは実用的ではありません。

于 2010-03-13T16:09:31.940 に答える
3

fseek(...)OS システムコールではなく、ライブラリコールです。OS へのシステム コールの実行に伴う実際のオーバーヘッドを処理するのはランタイム ライブラリです。技術的に言えば、fseek は間接的にシステムへの呼び出しを行っていますが、実際にはそうではありません (これにより、ライブラリ コールとシステム コールの違い)。fseek(...)基礎となるシステムに関係なく、標準の入出力関数です...しかし...そしてこれは大きなものです...

OS はファイルをカーネル メモリにキャッシュしている可能性が高くなります。つまり、1 と 0 が格納されているディスク上の場所への直接オフセットです。これは、OS のカーネル レイヤーを介して行われます。ファイルが構成されているもののスナップショットを持つ、カーネル内の最上位レイヤー。つまり、含まれているものに関係なくデータです (そのオフセットのディスク構造への「ポインター」がある限り、どちらの方法でもかまいません)。ディスク上の lcoation は有効です!)...

発生すると、大量のオーバーヘッドfseek(..)が発生し、間接的にカーネルがディスクからの読み取りタスクを委任します。これは、ファイルがどの程度断片化されているかに応じて、理論的には「いたるところに」発生する可能性があります。ユーザーランドの観点から、つまりCコードfseek(...)が.ファイルの途中に挿入すると (この段階で、カーネルはデータの実際のディスク プラッターに位置/オフセットを調整する必要があることを思い出してください)、ファイルの最後に追加するよりも遅いと見なされます。

理由は非常に単純です。カーネルは最後のオフセットが何であったかを「認識」しており、EOF マーカーを消去してさらにデータを挿入するだけです。裏で、カーネルはディスク バッファーに別のメモリ ブロックを割り当てなければなりません。データの追加が完了すると、EOF マーカーに続くディスク上の位置への調整されたオフセット。

于 2010-03-13T16:39:08.323 に答える
2

Solarisについて私が観察したことの 1 つfseekは、Solaris を呼び出すたびにFILE. 次の読み取りでは、常に完全なブロック (デフォルトでは 8K) が読み取られます。したがって、小さな読み取りで多くのランダムアクセスがある場合は、バッファなしで (バッファsetvbufを使用しNULLて) 実行するか、直接 syscall を使用することをお勧めします ( lseek+readまたはpread2 ではなく 1 syscall であるほうがよい)。この動作は、他の OS でも同様であると思います。

于 2010-08-29T18:48:11.147 に答える
1

ファイルの途中にデータを挿入すると、末尾に追加するよりも効率が低下します。これは、挿入するときに挿入ポイントの後にデータを移動して、挿入するデータ用のスペースを確保する必要があるためです。これらのデータを移動するには、ディスクからデータを読み取り、挿入するデータを書き込み、挿入されたデータの後に古いデータを書き込む必要があります。したがって、挿入時に少なくとも 1 つの余分な読み取りと書き込みがあります。

于 2010-03-13T16:31:25.057 に答える
1

データ サイズが FS セクタの倍数である場合にのみ、ファイルの途中にデータを効率的に挿入できますが、OS にはそのような機能がないため、FS ドライバへの低レベル インターフェイスを使用する必要があります。

于 2010-03-13T16:03:39.193 に答える