Miért függ a `BrokenPipeError` a vezetett adatfolyam méretétől?
On február 15, 2021 by admin A következő szkript felveti a (z) BrokenPipeError: [Errno 32] Broken pipe
parancsot, amikor olyan parancshoz vezetik, mint például: head
(hacsak a fejlendő sorok száma nem haladja meg a Python szkript által kinyomtatott sorok számát).
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
Megértésem ( ez a válasz és az válasz erre a kérdésre ) az, hogy hiba lép fel, ha egy csövet bezárnak, mielőtt a Python folyamat befejeződik írok neki.
Ha azonban csökkentem az iterált tartományt eggyel 16385-re, akkor a hiba nem merül fel (nem biztos, hogy ez a küszöb megegyezik-e az összes gépen, ezért lehet, hogy csak egy magas és alacsony számot próbál meg szaporodni). Kezdetben azt gondoltam, hogy ez összefüggésben lehet a csőpuffer méretével, de ez számomra 64K (a M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
szerint, tehát úgy tűnik, hogy nem ez az oka.
Miért függ a BrokenPipeError
előfordulás a piped méretétől?
Ez a Python 3.8.1 verziónál van a Linux 5.4.15-arch1 alatt -1.
Megjegyzések
Válasz
Miért függ az eseményBrokenPipeError a pipa méretétől?
Mivel több dolog megírása több időt vesz igénybe, és a csővezeték jobb oldala meghalhat, mielőtt a python befejezné az írást. Továbbá, ha a python megpróbál többet írni, mint amennyi a csőpufferben elfér, akkor blokkol, és elegendő időt ad a head -1
számára a kilépéshez.
Mivel a head -1
némi időbe telik élni és meghalni, a python felhasználhatja ezt az időt az összes cuccának megírására – ha elfér a csőpufferben – és sikeresen kilép. Ezt nehéz megjósolni, mivel a kern szabadon ütemezheti a csővezeték mindkét oldalát tetszőleges sorrendben, és késleltetheti a head -1
indítását, amíg jónak látja, vagy bármikor állítsa le.
>>> 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!
De ha a python megpróbál több dolgot írni, mint amennyit a pipába elfér, menthetetlenül kap egy EPIPE
vagy SIGPIPE
a végén, függetlenül attól, hogy mennyi ideje van:
>>> 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
de ez számomra 64K … tehát úgy tűnik, hogy nem ez az oka.
Ne feledje, hogy a python teljes pufferelést használ, ha a kimenet nem terminál; nem “soronként vagy byte-onként, hanem valamilyen méretű darabokkal ír:
>>> 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 +++
:
paranccsal ahead -1
parancs helyett.python3 -c "for i in range(10000): print(i)" | : </dev/tcp/unix.stackexchange.com/https
. Ha duplázol / hármas a tartomány, a python a hibával a Broken Pipe használatával.