web-dev-qa-db-ja.com

非常に大きな出力の配管コマンド

ディレクトリをtarして結果をstdoutに書き込み、それを次のように圧縮プログラムにパイプします。

tar -cvf - /tmp/source-dir | lzip -o /media/my-usb/result.lz -

数行のテキストを出力するコマンドでパイプをずっと使用しています。 tarのような非常に大きな出力を持つ(高速)コマンドをパイプ処理し、その後に非常に遅い圧縮コマンドを実行するとどうなるのでしょうか。 tarは、その出力がlzipによって消費されるのを待ちますか?それとも、すべてをRAMに出力できるのと同じくらい高速に動作しますか?後者が本当なら、低システムでの惨事になるRAM=システム。

19
Livy

データプロデューサー(tar)がコンシューマー(lzip)がすべてを読み取る時間を確保できないほど速くパイプに書き込もうとすると、lziptarが書き込んでいる内容を読み取る時間がなくなるまでブロックされます。パイプに関連付けられた小さなバッファーがありますが、そのサイズはほとんどのtarアーカイブのサイズよりも小さい可能性があります。

「ブロッキング」とは単に、tarwrite()ライブラリ関数(または同等の関数)を呼び出したときに、データがパイプバッファーに送信されるまで呼び出しが返されないことを意味します。 lzipが同じバッファーからの読み取りに時間がかかる場合の時間。これをtopで確認できるはずです。tarは、lzipと比較して速度が低下し、多くの時間スリープします(tarは実際にはlzipより速いと想定しています)。

したがって、notパイプラインでRAMのかなりの量を埋めます。これを行うには(必要に応じて)、中央にpvのようなものを使用できます、いくつかのバッファ付き:

_tar -cvf - /tmp/source-dir | pv --buffer-size 1G | lzip -o /media/my-usb/result.lz -
_

これにより、tarがブロックするたびにpvがブロックされます。 pvは、バッファがいっぱいになり、lzipに書き込めない場合にブロックします。


逆の状況も同様に機能します。つまり、パイプの左側が遅く右側が高速である場合、右側のコンシューマーはデータがあるまでread()をブロックしますパイプから読み取られる。

これ(データI/O)は、パイプラインに参加するプロセスを同期する唯一のものです。読み取りと書き込み(および他の誰かが読み取りまたは書き込みを行うのを待つ間、時々ブロックする)を除いて、それらは互いに独立して実行されます。

44
Kusalananda

GNU tarには-lzipへの-lzipオプションがあるため、代わりに使用することができます。

tar -cvf --lzip /media/my-usb/result.lz /tmp/source-dir

質問への回答:あなたの場合、システムはデフォルトのシステムバッファーサイズを使用してパイプを適切に管理します。

2
Yurko