Python Socket.IO/AIOHTTP服务器async/await机制问题排查
为什么Python-Socket.IO的async处理函数加sleep后只收到第一条消息?
首先澄清你的误区:async函数并不是只能同时运行一个实例,问题出在两个关键地方——你的客户端进程过早退出,以及Python-Socket.IO默认对单个客户端的事件采用串行处理的机制。
1. 客户端进程过早退出是直接原因
看你的Node.js客户端代码,在连续调用三次emit后,进程没有任何后续异步任务,会立刻退出,导致Socket连接被强制断开。这时候服务器可能只接收到第一条消息,或者后两条消息还没来得及发送/处理,连接就已经断了。
你可以修改客户端代码,让它保持连接一段时间,确保服务器有足够时间处理所有消息:
const io = require('socket.io-client'); const socket = io('ws://localhost:8080'); // 等连接建立后再发送消息更可靠 socket.on('connect', () => { socket.emit('sendText', 'hey 1'); socket.emit('sendText', 'hey 2'); socket.emit('sendText', 'hey 3'); }); // 保持进程运行,避免过早退出 setTimeout(() => { socket.disconnect(); process.exit(); }, 5000); // 等待5秒确保所有消息处理完成
2. Python-Socket.IO的单客户端事件串行处理机制
即使客户端保持连接,你也会发现三条消息的处理是按顺序来的——第一条处理完(sleep结束),才会开始处理第二条。这是因为Python-Socket.IO默认对同一个客户端(同一个sid)的所有事件采用串行处理:每个客户端有一个独立的事件队列,前一个事件的处理函数执行完成前,后面的事件会被排队等待,不会触发处理。
如果你希望同一个客户端的事件可以并发处理,不要在事件处理函数里直接执行耗时的await操作,而是用sio.start_background_task把耗时逻辑放到后台任务中,让事件处理函数立刻返回,这样后续事件可以被及时处理:
import asyncio from aiohttp import web import socketio import random sio = socketio.AsyncServer(async_mode='aiohttp') app = web.Application() sio.attach(app) @sio.on('connect') def connect(sid, environ): print("connected: ", sid) @sio.on('sendText') async def message(sid, data): print("message ", data) # 启动后台任务处理耗时操作,当前函数立刻返回 await sio.start_background_task(handle_delayed_log, data) async def handle_delayed_log(data): await asyncio.sleep(1 * random.random()) print('waited', data) @sio.on('disconnect') def disconnect(sid): print('disconnect ', sid) if __name__ == '__main__': web.run_app(app, host='0.0.0.0', port=8080)
这样修改后,三条消息的print("message ", data)会立刻依次输出,而waited的输出则会随机延迟,互不阻塞。
内容的提问来源于stack exchange,提问作者Julius
相关产品推荐
相关产品推荐

