バッファ付きIOとバッファなしIO


83

プログラムのI / Oはデフォルトでバッファリングされていること、つまり、一時ストレージから要求元のプログラムに提供されることを学びました。バッファリングによってIOパフォーマンスが向上することを理解しています(おそらくシステムコールを減らすことによって)。setvbufCのように、バッファリングを無効にする例を見てきました。2つのモードの違いは何ですか。また、どちらをいつ使用する必要がありますか。

回答:


123

続行する前に出力が書き込まれたことを確認する場合は常に、バッファなしの出力が必要です。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                |
+---------------------------------------+

グラフは素晴らしいです。言及する価値のあることの1つは、FILEオブジェクト(ストリーム)の内部バッファーが、fgets必要なバッファーパラメーターとは完全に異なることです。これは、私がそれを理解するためのコードを書く前に、何時間も私を混乱させました。QAQ
リック

35

ディスクに書き込む準備ができているバイトの大きなシーケンスがすでにある場合は、バッファなしの出力が必要であり、途中の2番目のバッファへの余分なコピー回避したい。

バッファリングされた出力ストリームは、書き込み結果を中間バッファに蓄積し、十分なデータが蓄積された(またはflush()要求された)場合にのみOSファイルシステムに送信します。これにより、ファイルシステムコールの数が減ります。ファイルシステムコールはほとんどのプラットフォームで高額になる可能性があるため(短いものと比較して)memcpy)、バッファリングされた出力は、多数の小さな書き込みを実行する場合の正味のメリットです。送信するバッファがすでに大きい場合は、通常、バッファなしの出力の方が適しています。中間バッファにコピーしても、OS呼び出しの数はさらに減らず、追加の作業が発生します。

バッファリングされていない出力は、データがディスクに到達することを保証することとは何の関係もありません。その機能はによって提供されflush()、バッファ付きストリームとバッファなしストリームの両方で機能します。バッファリングされていないIO書き込みは、データが物理ディスクに到達したことを保証するものではありません。OSファイルシステムは、データのコピーを無期限に保持し、必要に応じてディスクに書き込むことはありません。を呼び出すときにのみ、ディスクにコミットする必要がありますflush()。(それclose()flush()あなたに代わって呼び出すことに注意してください)。


呼び出しflush()はそれがディスクに書き込まれることを保証しますか?私はそれをディスクのバッファに渡すだけだと思いました。
jrdioko 2011

2
O_SYNC書き込みを保証する必要があります。
moshbear 2011

ディスクへの書き込みに関するバッファリングされていないIOks。したがって、winapiのバッファなし(中間バッファはないがディスクに直接書き込まれる)という用語は、FILE_FLAG_NO_BUFFERINGおよびFILE_FLAG_WRITE_THROUGHを指定してCreateFileを呼び出し、各書き込み後にデータが直接永続化されるようにします。他のいくつかのOSについてはわかりません。
Martin Kosicky
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.