Ruby のバッファリングされた IO ストリーム


オブジェクトの永続性



コンソールには、非常に重要な情報がいくつかあります.

> data = "some really important information"
=> "some really important information"


その情報をディスクに保存したいのですが、それは一時的なものです. Ruby に組み込まれている Tempfile を使用しますが、これを使用する必要があります.

> require "tempfile"
> file = Tempfile.new


これにより、ディスク上に新しい一時ファイルが作成されます.これは新しいため、現在は空です.これを 2 つの異なる方法で確認します.

> File.size(file.path)
=> 0
> file.size
=> 0


最後に、いくつかの非常に重要な情報をディスクに書き込むことができます.その後、サイズを再度確認します.

> file.write(data)
=> 33
> File.size(file.path)
=> 0
> file.size
=> 33


write を IO ストリーム (この場合はファイル) に送信すると、書き込まれたバイト数 33 が返されます.ファイルに書き込んだ後、ファイルのサイズを File.size で尋ねたところ、0 が返されました.次に、ファイルのサイズを尋ねたところ、33 が返されました.

その文字列はどこにありますか?



文字列がディスクにコミットされる前に、メモリ内のファイル インスタンスに書き込まれた可能性があります.オブジェクトの size を見てみましょう.

> require "objspace"
> ObjectSpace.memsize_of(data)
=> 40
> ObjectSpace.memsize_of(file)
=> 80


さて、 memsize_of はヒント/推測です-ドキュメントはそれについて明確です:

Note that the return size is incomplete. You need to deal with this information as only a HINT.



これでうまくいきます.それを使用して、それがまったく変更されたかどうかを確認します.

ファイルが現在メモリ内に 80 バイトあることを確認したので、もう一度書き込みを試みましょう.

> file.write(data)
=> 33
> ObjectSpace.memsize_of(file)
=> 80

file オブジェクト自体のサイズは変わらないので、そこに隠れていないのでしょう.

前に見たように、パスを File.size に渡しても、ファイルに書き込まれる新しく書き込まれたバイトは表示されませんが、file インスタンス自体に size を要求すると表示されます.

また、 file.size を要求した後、 File.size(file.path) には、新しく書き込まれたバイトを含むサイズがあります.したがって、最終的にはファイルのサイズに同意します.

> File.size(file.path)
=> 33
> file.size
=> 66
> File.size(file.path)
=> 66


違いのサイズアップ



ファイル インスタンスで size を呼び出すと、documented という副作用があります.

As a side effect, the IO buffer is flushed before determining the size.



これは、文字列を書いた後にどこに行ったのかを説明しています! RubyのIOバッファに格納されていました.バッファー pushes の内容をオペレーティング システムにフラッシュします.

ファイルのサイズを確認し、より多くのバイトを書き込み、ファイルのサイズが変わらないことを確認し、バッファを明示的にフラッシュすることを観察してみましょう.

バッファをフラッシュした後、ファイルのサイズは書き込まれたバイト数だけ変化します.

> File.size(file.path)
=> 66
> file.write(data)
=> 33
> File.size(file.path)
=> 66
> file.flush
> File.size(file.path)
=> 99


Rewinding 書き込み後のファイルもバッファをフラッシュしているように見えます.

> File.size(file.path)
=> 99
> file.write(data)
=> 33
> File.size(file.path)
=> 99
> file.rewind
=> 0
> File.size(file.path)
=> 132


バッファリングなし



ストリームの sync mode を設定することで、Ruby の IO バッファをバイパスできます.デフォルトでは、これはバッファに設定されています.ただし、これを true に設定すると、ストリームの内容がすぐにオペレーティング システムにフラッシュされます.

> new_file = Tempfile.new
> new_file.sync
=> false
> new_file.sync = true
> streaming = "no buffering"
> File.size(new_file.path)
=> 0
> new_file.write(streaming)
=> 12
> File.size(new_file.path)
=> 12

File.size は、直接または副作用としてそうする方法を介して、バッファをフラッシュする必要なく、ファイル内のバイトを認識しています.同期モードでは、書き込む内容を直接ディスクにプッシュします (少なくとも、オペレーティング システムを介して).

ストリームを閉じる



Ruby は書き込みをファイルなどの IO ストリームにバッファリングします.そのバッファがフラッシュされるタイミングと場合に注意する必要があります.ストリームへの書き込みが書き込み対象のアイテムに与える影響をすぐに確認する必要があります.

This post originally published on The Gnar Company blog.