WebSockets服务器阻塞请求下消息发送异常及send机制咨询
核心原因:阻塞IO卡住了异步事件循环
你遇到的问题本质是在异步WebSocket服务里用了阻塞式的requests.get,直接卡死了整个事件循环,导致后续的WebSocket消息发送任务没法被及时调度执行。
为什么消息会堆积到阻塞操作结束后才一起发送?
首先纠正一个误解:await websocket.send()返回时,消息不一定已经被实际发送到网络上。异步WebSocket的send操作只是把消息放到了发送缓冲区/队列里,真正的网络发送动作是由异步事件循环调度底层IO组件完成的。
当你调用阻塞的requests.get时,这个操作会占用当前线程(异步框架的事件循环一般是单线程)的所有时间,事件循环根本没法去处理WebSocket的发送任务——也就是说,后面几次send只是把消息塞进了队列,但没人去触发实际的网络发送。直到所有requests.get都执行完,事件循环重新恢复运行,才会一次性把队列里堆积的消息全部发出去,所以客户端会在长时间后同时收到这些消息。
为什么第一条消息能立即收到?
第一次await websocket.send("request sent")执行时,事件循环还没被阻塞。此时send把消息放进队列后,事件循环能立刻调度底层IO完成发送,所以客户端能马上收到。
紧接着你调用了requests.get,这个阻塞操作直接把事件循环“按住”了,后面的几次send虽然代码上执行了,但消息都只能堆在缓冲区里,直到阻塞操作结束才被批量发送。
为什么改用aiohttp就正常?
aiohttp的请求是异步非阻塞的,await aiohttp.get()不会卡住事件循环——每次请求等待响应时,事件循环可以去处理其他任务(比如WebSocket的发送),所以每一次send之后,消息都能被及时调度发送,客户端就能依次收到进度消息。
内容的提问来源于stack exchange,提问作者Ali Al-Alak

