Может ли [BlockingIOError
в асинхронном ридере] вообще никогда не происходить, логически? Если это возможно, при каких обстоятельствах?
Ответ на этот вопрос почти наверняка будет зависеть от системы. Сам Python не предоставляет никаких гарантий по этому вопросу: такие функции, как os.read
и socket.recv
, просто проверяют значение, возвращаемое базовым системным вызовом, и, если это указывает на ошибку, продолжают преобразовывать системную ошибку в Исключение Python.
Таким образом, вопрос сводится к тому, может ли чтение из сокета потерпеть неудачу с EAGAIN
или эквивалентным, если предыдущий опрос / выбор показал, что он был читаем (и эквивалент для записи). Хотя это, безусловно, звучит как ненормальная ситуация, select(2)
man-страница явно предупреждает об этом в разделе BUGS:
В Linux select()
может сообщать дескриптор файла сокета как «готовый к чтению», но, тем не менее, при последующем чтении блокируется. Это может, например, произойти, когда данные поступили, но при проверке они имеют неверную контрольную сумму и отбрасываются. Могут быть другие обстоятельства, при которых файловый дескриптор ложно сообщается как готовый. Таким образом, может быть безопаснее использовать O_NONBLOCK
на сокетах, которые не должны блокировать.
В случае неблокирующих сокетов следует читать «тем не менее последующие блоки чтения» как «тем не менее последующее чтение завершается неудачно с EAGAIN
», и предупреждение относится к этому вопросу. Эта проблема также не относится к select()
; Страница справочника poll(2)
также упоминает о ложных пробуждениях в разделе ошибок, обращаясь к руководству select(2)
за подробностями.
Другими словами, переносимый код не должен полагаться на чтение из «читаемых» сокетов, никогда не повышающее BlockingIOError
. Asyncio не полагается на него: он реагирует на EAGAIN
, просто , не завершая будущее , и таким образом повторно приостанавливает сопрограмму, ожидающую чтения.