服务器关闭连接时,
sock_recv返回一个空的字节数组(
b''),表示文件结束。由于您不处理该条件,因此您的代码最终陷入了处理相同缓冲区的无限循环中。
要更正它,请添加以下内容:
if data == b'': break
…
data = await loop.sock_recv(...)行后
但是上面仍然没有解释为什么
wait_for不能取消无赖协程。问题是
await,正如有时可以理解的那样,这并不意味着“将控制传递给事件循环”。它的意思是“从提供的等待对象中请求值,
如果 (并且只要)对象指示它没有准备好值,就将控制权交给事件循环。” 该 如果 是至关重要的:如果对象 确实
已经准备好时,首先询问,该值将被立即使用而不用推迟事件循环的值。换句话说,
await不能保证事件循环有运行的机会。
例如,下面的协程完全阻塞事件循环和防止以往任何时候都在运行,尽管它的内环由没有任何其他的协程 ,但 等待:
async def busy_loop(): while True: await noop()async def noop(): pass
在您的示例中,由于套接字在文件结束时根本不会阻塞,因此协程永远不会挂起,并且(与上述错误共同作用)协程永远不会退出。
为了确保其他任务有运行的机会,您可以添加
awaitasyncio.sleep(0)一个循环。对于大多数代码而言,这不是必需的,因为在这些情况下,请求IO数据将很快导致等待,这时将触发事件循环。(实际上,经常需要这样做表明存在设计缺陷。)仅与EOF处理错误结合在一起,使代码卡住。



