Python Pipes-出力をインクリメンタルに読み取るときの動作
質問
パイプの一般的な使用法は、 圧縮ファイルの増分;それ 全体を解凍せずに 一度に。次の機能 圧縮ファイルの名前を次のように取ります パラメータであり、パイプを返します gunzipを使用して解凍します 内容:
def open_gunzip(filename): cmd = 'gunzip -c ' + filename fp = os.popen(cmd) return fp
fpから1行を読み取る場合 時間、保存する必要はありません メモリ内または上の非圧縮ファイル ディスク。
たぶん私はこれを間違って解釈しているだけかもしれませんが、これがどのように可能かはわかりません。 Pythonには、結果を吐き出す途中でgunzipを一時停止する手段がありませんでしたか?より多くの行を出力し続ける前に、出力の行が読み取られるまでgunzipがブロックされないと想定しているため、一部のバッファーは、このすべてをキャプチャする必要があります(Pythonインタープリターの内部またはOS、メモリまたはディスク) )、非圧縮ファイルが完全にどこかに保存されていることを意味します...右?
解決
仮定に誤りがあります。 gunzipは、ファイル全体を参照して解凍する必要はありません。解凍ファイル形式を読みます。個々のコンポーネントへのオフセットを持つディレクトリがあります。
ファイルを分割して解凍することは可能です。
"非圧縮ファイルはどこかに完全に保存されています...右?"
必ずしもそうではありません。なぜそれを仮定しているのか、どこで読んだのかわからない。
すべての低レベルI / O呼び出しはブロックできます。 gunzipでの書き込み(パイプへの書き込み時)は、パイプバッファーがいっぱいになるとブロックできます。これがパイプへのI / Oの定義方法です。パイプI / Oブロック。
詳細については、パイプのmanページを確認してください。
プロセスが 空のパイプ、それからread(2)は
データが利用可能になるまでブロックします。もし プロセスは、
フルパイプ(以下を参照)、次にwrite(2) 十分なデータがなくなるまでブロックします
許可するためにパイプから読み取られた 完了して書き込みます。ノンブロッキング
I / Oは、fcntl(2)を使用して可能です。 F_SETFL操作により、
O_NONBLOCKオープンファイルステータスフラグ。
他のヒント
これは、Pythonではなく、 gunzip
の実装に由来します。
Cで書かれています。おそらく、Cの stdio.h
の fwrite()
を使用して、その出力を書き込みます。
libc6
実装は自動的に出力バッファーを作成し、いっぱいになると、さらに書き込めるまで fwrite()
をブロックします。
gunzip
を一時停止しているのはPythonではなく、カーネルが( write()
を使用して、書き込みを試みると gunzip
の実行を停止することですsyscall)をフルバッファーに。これは、 IOのブロックと呼ばれます。カーネルは、パイプを読み書きするプロセスで発生するバッファリングとは無関係に、パイプラインの両端を接続する内部バッファーを維持します。
Pythonは、空のバッファーを持つパイプ、つまり現在 gunzip
からのデータが書き込まれていないパイプから読み取るときに同様にブロックします。
パイプは、生産者と消費者の問題に対する解決策と見なすことができます。