Pourquoi `BrokenPipeError` dépend-il de la taille du flux canalisé?
On février 15, 2021 by admin Le script suivant déclenche BrokenPipeError: [Errno 32] Broken pipe
, lorsquil est redirigé vers une commande telle que head
(sauf si le nombre de lignes à en-tête dépasse le nombre de lignes imprimées par le script 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
Ma compréhension (de cette réponse et les réponses à cette question ) est quune erreur est générée si un tube est fermé avant la fin du processus Python lécriture.
Cependant, si je décrémente la plage itérée de un à 16385, lerreur nest pas levée (je ne sais pas si ce seuil est le même sur toutes les machines, alors essayez simplement un nombre haut et bas reproduire). Jai dabord pensé que cela pouvait être lié à la taille de la mémoire tampon du tube, mais cest 64K pour moi (selon M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
, donc cela ne semble pas être la raison.
Pourquoi loccurrence BrokenPipeError
dépend-elle de la taille de ce qui est diffusé?
Cest avec Python 3.8.1 sous Linux 5.4.15-arch1 -1.
Commentaires
Answer
Pourquoi loccurrenceBrokenPipeError dépend-elle de la taille de ce qui est diffusé?
Parce quécrire plus de choses prend plus de temps, et le côté droit du pipeline peut mourir avant que votre python nait fini de lécrire. De plus, si le python essaie décrire plus quil nen tient dans le tampon du tube, il bloquera et donnera à head -1
suffisamment de temps pour quitter.
Depuis le head -1
div id = « 9ecbb874ef »>
prend un certain temps à vivre et à mourir, le python peut utiliser ce temps pour écrire tout son contenu – sil tient dans le tampon du tube – et sortir avec succès. Cest difficile à prévoir, car le noyau est libre de planifier les deux côtés du pipeline dans nimporte quel ordre, et peut retarder le démarrage de head -1
aussi longtemps quil le juge opportun, ou il peut arrêtez-le à tout moment.
>>> 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!
Mais si python essaie décrire plus de choses quil nen tient dans le tube, il obtiendra inexorablement un EPIPE
ou SIGPIPE
à la fin, quel que soit le temps dont il dispose:
>>> 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
mais cest 64K pour moi … donc cela ne semble pas être la raison.
Gardez à lesprit que python utilise la mise en mémoire tampon complète lorsque la sortie nest pas un terminal; il nécrit pas ligne par ligne ou octet par octet, mais par morceaux de une taille:
>>> 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 +++
:
au lieu de la commandehead -1
.python3 -c "for i in range(10000): print(i)" | : </dev/tcp/unix.stackexchange.com/https
. Si vous double / triple la plage, le python avec échec avec Broken Pipe.