Почему `BrokenPipeError` зависит от размера передаваемого потока?

Если ваше ядро ​​поддерживает контроллер памяти cgroup v1 и он включен (, насколько мне известно, он включен во всех основных дистрибутивах Linux ), вы сможете использовать значение root memory.max_usage_in_bytesдля этого:

echo "$(("$(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes)" / 2**20)) MB"
2
04.02.2020, 17:47
1 ответ

Why is the occurrenceBrokenPipeError dependent on the size of what is being piped?

Потому что для написания большего количества материала требуется больше времени, и правая часть конвейера может умереть до того, как ваш питон закончит ее писать. Кроме того, если python попытается записать больше, чем помещается в буфер канала, он заблокируется и даст head -1достаточно времени для выхода.

Поскольку head -1требуется некоторое время, чтобы жить и умирать, python может использовать это время для записи всего своего материала --, если он помещается в буфер конвейера --и успешно завершает работу. Это трудно предсказать, поскольку ядро ​​может планировать обе стороны конвейера в любом порядке и может откладывать запуск head -1до тех пор, пока считает нужным, или может остановить его в любое время.

>>> 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!

Но если python попытается написать больше материала, чем умещается в конвейере, он неизбежно получит EPIPEили SIGPIPEв конце, независимо от того, сколько времени у него есть:

>>> 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

but that is 64K for me... so that doesn't seem to be the reason.

Имейте в виду, что python использует полную буферизацию , когда вывод не является терминалом; он пишет не построчно или байт за байтом, а кусками некоторого размера:

>>> 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 +++
2
28.04.2021, 23:24

Теги

Похожие вопросы