Warum hängt BrokenPipeError von der Größe des Piped-Streams ab?
On Februar 15, 2021 by admin Das folgende Skript löst BrokenPipeError: [Errno 32] Broken pipe
aus, wenn es an einen Befehl wie head
(es sei denn, die Anzahl der zu überschreibenden Zeilen überschreitet die Anzahl der vom Python-Skript gedruckten Zeilen).
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
Mein Verständnis (von Diese Antwort und die Antwort auf diese Frage ) ist, dass ein Fehler ausgelöst wird, wenn eine Pipe geschlossen wird, bevor der Python-Prozess abgeschlossen ist Schreiben darauf.
Wenn ich jedoch den iterierten Bereich um eins auf 16385 dekrementiere, wird der Fehler nicht ausgelöst (nicht sicher, ob dieser Schwellenwert auf allen Computern gleich ist, versuchen Sie es also einfach mit einer hohen und einer niedrigen Zahl reproduzieren). Anfangs dachte ich, dies könnte mit der Größe des Pipe-Puffers zusammenhängen, aber das sind 64 KB für mich (gemäß M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
, sodass dies nicht der Grund zu sein scheint.
Warum hängt das Vorkommen BrokenPipeError
von der Größe der Pipings ab?
Dies ist bei Python 3.8.1 unter Linux 5.4.15-arch1 der Fall -1.
Kommentare
- Hier ' eine Herausforderung: Demonstrieren Sie die Prämisse Ihrer Frage, dass Es besteht eine Größenabhängigkeit, bei der der Befehl
:
anstelle des Befehlshead -1
verwendet wird. - Haben Sie die Standardeinstellung überprüft? Die Pufferkapazität einer Pipe befindet sich auf Ihrem System? Ich wette, ' liegt nahe bei 16 KB …
- @Useless " Ich wette, " Sie verlieren.
- @JdeBP mit bash:
python3 -c "for i in range(10000): print(i)" | : </dev/tcp/unix.stackexchange.com/https
. Wenn Sie verdoppeln / verdreifachen der Bereich, die Python mit Fail mit Broken Pipe.
Antwort
Warum hängt der VorkommenBrokenPipeError von der Größe der Rohrleitungen ab?
Weil das Schreiben von mehr Material mehr Zeit in Anspruch nimmt und die rechte Seite der Pipeline möglicherweise stirbt, bevor Ihre Python das Schreiben beendet hat. Wenn der Python versucht, mehr zu schreiben, als in den Pipe-Puffer passt, blockiert er und gibt dem head -1
ausreichend Zeit zum Beenden.
Seit dem head -1
braucht einige Zeit, um zu leben und zu sterben. Die Python kann diese Zeit nutzen, um all ihre Sachen zu schreiben – wenn sie in den Pipe-Puffer passen – und erfolgreich zu beenden. Dies ist schwer vorherzusagen, da der Kernel beide Seiten der Pipeline in beliebiger Reihenfolge planen kann und das Starten des head -1
verzögern kann, solange er dies für richtig hält Stoppen Sie es jederzeit.
>>> 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!
Wenn Python jedoch versucht, mehr Inhalte zu schreiben, als in die Pipe passen, wird unaufhaltsam eine EPIPE
oder SIGPIPE
am Ende, egal wie viel Zeit es hat:
>>> 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
, aber das sind 64 KB für mich … das scheint also nicht der Grund zu sein.
Beachten Sie, dass Python vollständige Pufferung verwendet, wenn die Ausgabe kein Terminal ist. Es wird nicht zeilenweise oder byteweise geschrieben, sondern nach Blöcken von einiger Größe:
>>> 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 +++
Schreibe einen Kommentar