sock.recvfrom
会向读者提出BlockingIOError
吗?如以下
sock.setblocking(False)
def reader()
try:
(data, addr) = sock.recvfrom(512)
except BlockingIOError:
# Can this ever be raised?
loop.add_reader(sock.fileno(), reader)
类似地,sock.send
可以向作家提出BlockingIOError
吗?
sock.setblocking(False)
def writer()
try:
bytes_sent = sock.send(data)
except BlockingIOError:
# Can this ever be raised?
loop.add_writer(sock.fileno(), writer)
我已经尝试通过发送/接收大量数据进行实验,但到目前为止从未发生过。从逻辑上说,它不可能真正发生吗?如果可以发生,在什么情况下?
答案 0 :(得分:1)
从逻辑上讲,[a
BlockingIOError
在异步阅读器中永远不会真正发生吗?如果可以发生,在什么情况下?
几乎可以肯定,这个问题的答案取决于系统。 Python本身对此不提供任何保证:os.read
和socket.recv
之类的函数仅检查基础系统调用返回的值,如果指示错误,则继续转换系统,为Python异常提供了错误。
因此,问题归结为:如果先前的轮询/选择已表明它是可读的(并且等同于写操作),那么从套接字的读取是否会失败并以EAGAIN
或等效的方法失败。虽然这听起来确实是异常情况,但select(2)
man page 明确在BUGS下警告了该情况:
在Linux下,
select()
可能会将套接字文件描述符报告为“准备读取”,但是随后的读取会阻塞。例如,这可能在数据到达但检查时校验和错误并被丢弃时发生。在其他情况下,文件描述符可能会虚假地报告为就绪。因此,在不应该阻塞的套接字上使用O_NONBLOCK
可能更安全。
对于非阻塞套接字,应该将“尽管如此,随后的读取仍会阻塞”读取为“尽管如此,后续读取仍会失败,EAGAIN
”,并且警告适用于此问题。这个问题也不是专门针对select()
的; poll(2)
man page在其“ BUGS”部分中还提到了虚假唤醒,有关详细信息,请参考select(2)
手册。
换句话说,可移植代码不应依赖于从不引发BlockingIOError
的“可读”套接字的读取。 Asyncio并不依赖它:它仅通过not completing the future对EAGAIN
做出反应,从而将等待读取的协程重新悬浮。