`BrokenPipeError`がパイプされたストリームのサイズに依存するのはなぜですか?
On 2月 15, 2021 by admin次のスクリプトは、head
<のようなコマンドにパイプされると、BrokenPipeError: [Errno 32] Broken pipe
を発生させます。 / div>(先頭の行数がPythonスクリプトによって出力される行数を超えない場合)
for i in range(16386): print("")
$ python test-pipe.py | head -1 Traceback (most recent call last): File "test-pipe.py", line 2, in <module> print("") BrokenPipeError: [Errno 32] Broken pipe
私の理解(この回答とこの質問への回答)は、Pythonプロセスが終了する前にパイプを閉じるとエラーが発生することです。
ただし、反復範囲を1から16385にデクリメントしても、エラーは発生しません(このしきい値がすべてのマシンで同じかどうかわからないため、高い数値と低い数値を試してみてください。再現する)。当初、これはパイプバッファのサイズに関連しているのではないかと思っていましたが、私にとっては64Kです(M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
によると、それが理由ではないようです。
オカレンスBrokenPipeError
がパイプされるもののサイズに依存するのはなぜですか?
これは、Linux5.4.15-arch1上のPython3.8.1の場合です。 -1。
コメント
回答
occurrationBrokenPipeErrorがパイプされるもののサイズに依存するのはなぜですか?
より多くのものを書くのに時間がかかり、Pythonが書き終える前にパイプラインの右側が死ぬ可能性があるためです。また、Pythonがパイプバッファに収まらない量を書き込もうとすると、ブロックされ、head -1
が終了するのに十分な時間が与えられます。
head -1
が生きて死ぬまでには少し時間がかかりますが、Pythonはその時間を使ってすべてのものを書き込み(パイプバッファーに収まる場合)、正常に終了する場合があります。カーネルはパイプラインの両側を任意の順序で自由にスケジュールでき、適切と思われる限りhead -1
の開始を遅らせる可能性があるため、これを予測するのは困難です。いつでも停止してください。
>>> python3 -c "for i in range(50000): print("")" | sleep .01 Traceback (most recent call last): File "<string>", line 1, in <module> BrokenPipeError: [Errno 32] Broken pipe >>> python3 -c "for i in range(50000): print("")" | sleep .1 # OK!
しかし、Pythonがパイプに収まらないほど多くのものを書き込もうとすると、容赦なくまたはSIGPIPE
は、どれだけ時間がかかっても、最終的には次のようになります。
>>> python3 -c "for i in range(100000): print("")" | sleep 20 Traceback (most recent call last): File "<string>", line 1, in <module> BrokenPipeError: [Errno 32] Broken pipe
しかし、それは私にとって64Kです…それが理由ではないようです。
出力が端末ではない場合、Pythonはフルバッファリングを使用していることに注意してください。行ごとまたはバイトごとに書き込むのではなく、一部のサイズのチャンクで書き込みます:
>>> strace -s3 -e trace=write python3 -c "for i in range(50000): print("")" | sleep .3 write(1, "\n\n\n"..., 8193) = 8193 write(1, "\n\n\n"..., 8193) = 8193 write(1, "\n\n\n"..., 8193) = 8193 write(1, "\n\n\n"..., 8193) = 8193 write(1, "\n\n\n"..., 8193) = 8193 write(1, "\n\n\n"..., 8193) = 8193 write(1, "\n\n\n"..., 842) = 842 +++ exited with 0 +++
head -1
コマンドの代わりに:
コマンドを使用して、サイズの依存関係が存在します。python3 -c "for i in range(10000): print(i)" | : </dev/tcp/unix.stackexchange.com/https
。2倍/ 3倍の場合範囲、壊れたパイプで失敗したpython。