FastAPI子进程中调用WebSocket发送数据无响应问题咨询
问题原因
- asyncio 封装的网络对象无法跨进程共享
你传入子进程的socket大概率是asyncio框架(如asyncio自带的流对象、aiohttp的WebSocket对象等)封装后的实例,这类对象内部绑定了主进程的事件循环、selector回调、内部状态缓冲区等上下文信息。即使在fork模式下子进程可以拿到该对象的内存拷贝,这些上下文和子进程内新启动的事件循环完全不兼容,调用send_json时实际写入动作没有执行,且框架默认不会抛出这类上下文不匹配的异常。
如果你的操作系统默认使用spawn模式启动子进程,这类不可序列化的asyncio对象会直接抛出异常,你没有遇到报错说明当前运行环境是fork模式。 - socket 文件描述符的跨进程操作冲突
即使你传递的是原始socket对象,该socket的文件描述符已经在主进程中被注册到主事件循环的IO多路复用器上,父子进程同时操作同一个文件描述符会出现状态竞争,内核会处理为写入动作无效,也不会触发用户态异常。
可行解决方案
- 方案1:传递原始socket文件描述符,子进程内重新封装
主进程只传递socket的文件描述符数值(调用原始socket的fileno()方法获取)到子进程,子进程内先通过socket.fromfd()方法重建原始socket实例,再将该实例绑定到子进程自己的asyncio事件循环上完成封装,之后再调用发送接口即可正常工作。 - 方案2:通过IPC中转待发送数据
不要在子进程中操作网络IO,主进程全权持有socket对象负责收发。父子进程通过multiprocessing.Queue或者Pipe传递待发送的数据,主进程从IPC通道拿到数据后,在自身的事件循环中调用send_json完成发送。 - 方案3:子进程独立创建socket连接
如果业务场景允许,不要跨进程传递socket相关对象,子进程启动后自行和对端建立新的socket连接,独立管理自身的网络IO生命周期,从根源上避免跨进程资源共享的问题。
内容的提问来源于stack exchange,提问作者Ferus
相关产品推荐
相关产品推荐

