Hvorfor er BrokenPipeError afhængig af størrelsen på den rørede strøm?
On februar 15, 2021 by admin Følgende script hæver BrokenPipeError: [Errno 32] Broken pipe
, når det sendes til en kommando som head
(medmindre antallet af linjer til hovedet overstiger antallet af linjer, der er udskrevet af Python-scriptet).
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
Min forståelse (fra dette svar og svar på dette spørgsmål ) er, at der rejses en fejl, hvis et rør lukkes, før Python-processen er afsluttet skriver til den.
Men hvis jeg mindsker det itererede interval med en til 16385, hæves fejlen ikke (ikke sikker på, om denne tærskel er den samme på alle maskiner, så prøv måske bare et højt og lavt tal at reproducere). Jeg troede oprindeligt, at dette muligvis var relateret til rørbufferstørrelsen, men det er 64K for mig (ifølge M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
, så det ser ikke ud til at være årsagen.
Hvorfor er forekomsten BrokenPipeError
afhængig af størrelsen på, hvad der bliver pipet?
Dette er med Python 3.8.1 på Linux 5.4.15-arch1 -1.
Kommentarer
Svar
Hvorfor er forekomstenBrokenPipeError afhængig af størrelsen på det, der røres?
Fordi at skrive flere ting tager mere tid, og højre side af rørledningen kan dø, før din python er færdig med at skrive den. Hvis python forsøger at skrive mere, end det passer i rørbufferen, blokerer det og giver head -1
rigelig tid til at afslutte.
Da head -1
tager noget tid at leve og dø, python bruger muligvis den tid til at skrive alle sine ting – hvis det passer i rørbufferen – og afslutte med succes. Det er svært at forudsige, da kernen er fri til at planlægge begge sider af rørledningen i en hvilken som helst rækkefølge og kan forsinke start af head -1
så længe den finder det passende, eller det kan stop det når som helst.
>>> 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!
Men hvis python forsøger at skrive flere ting, end det passer i røret, får det ubønhørligt en EPIPE
eller SIGPIPE
i sidste ende, uanset hvor meget tid det har:
>>> 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
men det er 64K for mig … så det ser ikke ud til at være årsagen.
Husk, at python bruger fuld buffering når output ikke er en terminal; det skriver ikke linje for linje eller byte for byte, men af klumper af noget størrelse:
>>> 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 +++
:
i stedet forhead -1
-kommandoen.python3 -c "for i in range(10000): print(i)" | : </dev/tcp/unix.stackexchange.com/https
. Hvis du fordobler / tredobler rækkevidden, python med fail med Broken Pipe.