プログラムのI / Oはデフォルトでバッファリングされていること、つまり、一時ストレージから要求元のプログラムに提供されることを学びました。バッファリングによってIOパフォーマンスが向上することを理解しています(おそらくシステムコールを減らすことによって)。setvbuf
Cのように、バッファリングを無効にする例を見てきました。2つのモードの違いは何ですか。また、どちらをいつ使用する必要がありますか。
回答:
続行する前に出力が書き込まれたことを確認する場合は常に、バッファなしの出力が必要です。1つの例は、Cランタイムライブラリでの標準エラーです。これは通常、デフォルトでバッファリングされていません。エラーは(うまくいけば)まれなので、すぐに知りたいと思います。一方、標準出力は、通過するデータがはるかに多いと想定されているという理由だけでバッファリングされます。
別の例は、ロギングライブラリです。ログメッセージがプロセス内のバッファ内に保持されており、プロセスがコアダンプを行う場合、出力が書き込まれない可能性が非常に高くなります。
さらに、最小化されるのはシステムコールだけでなく、ディスクI / Oも同様です。プログラムが一度に1バイトずつファイルを読み取るとしましょう。バッファリングされていない入力では、とにかくブロック全体を読み取る必要がある場合でも、バイトごとに(比較的非常に遅い)ディスクに移動します(ディスクハードウェア自体にバッファがある場合がありますが、それでもディスクコントローラに移動します)これは、メモリ内アクセスよりも遅くなります)。
バッファリングにより、ブロック全体が一度にバッファに読み込まれ、個々のバイトが(メモリ内の非常に高速な)バッファ領域から配信されます。
バッファリングは、次の例のように、さまざまな形式をとることができることに注意してください。
+-------------------+-------------------+
| Process A | Process B |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
| OS caches | Operating system buffers
+---------------------------------------+
| Disk controller hardware cache | Disk hardware buffers
+---------------------------------------+
| Disk |
+---------------------------------------+
ディスクに書き込む準備ができているバイトの大きなシーケンスがすでにある場合は、バッファなしの出力が必要であり、途中の2番目のバッファへの余分なコピーを回避したい。
バッファリングされた出力ストリームは、書き込み結果を中間バッファに蓄積し、十分なデータが蓄積された(またはflush()
要求された)場合にのみOSファイルシステムに送信します。これにより、ファイルシステムコールの数が減ります。ファイルシステムコールはほとんどのプラットフォームで高額になる可能性があるため(短いものと比較して)memcpy
)、バッファリングされた出力は、多数の小さな書き込みを実行する場合の正味のメリットです。送信するバッファがすでに大きい場合は、通常、バッファなしの出力の方が適しています。中間バッファにコピーしても、OS呼び出しの数はさらに減らず、追加の作業が発生します。
バッファリングされていない出力は、データがディスクに到達することを保証することとは何の関係もありません。その機能はによって提供されflush()
、バッファ付きストリームとバッファなしストリームの両方で機能します。バッファリングされていないIO書き込みは、データが物理ディスクに到達したことを保証するものではありません。OSファイルシステムは、データのコピーを無期限に保持し、必要に応じてディスクに書き込むことはありません。を呼び出すときにのみ、ディスクにコミットする必要がありますflush()
。(それclose()
はflush()
あなたに代わって呼び出すことに注意してください)。
flush()
はそれがディスクに書き込まれることを保証しますか?私はそれをディスクのバッファに渡すだけだと思いました。
O_SYNC
書き込みを保証する必要があります。
FILE
オブジェクト(ストリーム)の内部バッファーが、fgets
必要なバッファーパラメーターとは完全に異なることです。これは、私がそれを理解するためのコードを書く前に、何時間も私を混乱させました。QAQ