Hvorfor er `BrokenPipeError` avhengig av størrelsen på strømmen med rør?
On februar 15, 2021 by admin Følgende skript reiser BrokenPipeError: [Errno 32] Broken pipe
, når den sendes til en kommando som head
(med mindre antall linjer til hodet overstiger antall linjer som er skrevet ut av Python-skriptet.
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 svaret og svarene på dette spørsmålet ) er at det oppstår en feil hvis et rør lukkes før Python-prosessen er ferdig skriver til den.
Men hvis jeg reduserer det itererte området med en til 16385, blir ikke feilen hevet (ikke sikker på om denne terskelen er den samme på alle maskiner, så kanskje bare prøv et høyt og lavt tall å reprodusere). Jeg trodde opprinnelig at dette kunne være relatert til rørbufferstørrelsen, men det er 64K for meg (ifølge M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
, så det ser ikke ut til å være grunnen.
Hvorfor er forekomsten BrokenPipeError
avhengig av størrelsen på det som blir pipet?
Dette er med Python 3.8.1 på Linux 5.4.15-arch1 -1.
Kommentarer
Svar
Hvorfor er forekomstBrokenPipeError avhengig av størrelsen på det som blir ledet?
Fordi det tar mer tid å skrive flere ting, og høyre side av rørledningen kan dø før pythonet ditt er ferdig med å skrive det. Hvis pythonen prøver å skrive mer enn den passer i rørbufferen, vil den også blokkere og gi head -1
god tid til å avslutte.
Siden head -1
tar litt tid å leve og dø, python kan bruke den tiden til å skrive alle tingene sine – hvis den passer i rørbufferen – og avslutte vellykket. Det er vanskelig å forutsi, siden kjernen er fri til å planlegge begge sider av rørledningen i en hvilken som helst rekkefølge, og kan utsette start av head -1
så lenge det ser hensiktsmessig, eller det kan stopp 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 prøver å skrive flere ting enn det passer i røret, vil det ubønnhørlig få en EPIPE
eller SIGPIPE
til slutt, uansett hvor lang 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 meg … så det ser ikke ut til å være grunnen.
Husk at python bruker full buffering når utgangen ikke er en terminal; det skriver ikke linje for linje eller byte for byte, men av biter av noe 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 dobler / tredobler rekkevidden, pythonet med fail med Broken Pipe.