如何在独立线程运行asyncio/websockets服务:线程无当前事件循环报错
问题背景
需要在已运行多个工作线程、承载各类业务逻辑的小型Python桌面应用中新增WebSocket能力,响应偶发的入站WebSocket请求。因对Python异步编程不熟悉,参考相关方案均无法正常运行,Python 3.8.10环境下运行最简复现代码时抛出错误:builtins.RuntimeError: There is no current event loop in thread 'Thread-1'。
复现代码如下:
# asamp.py import time import datetime import asyncio import websockets import threading def bgWorker_SK(): # 单连接处理逻辑 async def handler(websocket, path): data = await websocket.recv() reply = f"Data recieved as: {data}!" await websocket.send(reply) start_server = websockets.serve(handler, "localhost", 5564) asyncio.loop.run_until_complete(start_server) asyncio.loop.run_forever() bgsk = threading.Thread(target=bgWorker_SK, daemon=True).start() if __name__ == '__main__': # 主线程持续执行业务逻辑 while True: print (datetime.datetime.now()) time.sleep(2)
错误原因
- Python 3.8 版本中,子线程默认不会自动创建绑定的事件循环,直接调用
asyncio.loop无法获取当前线程对应的事件循环对象,直接触发运行时错误。 - 原代码未给运行WebSocket服务的子线程单独创建、绑定专属事件循环,是报错的核心诱因。
修复方案
不需要大规模改造原有同步业务逻辑,只需要在子线程启动异步逻辑前,手动为该线程创建并绑定独立事件循环即可,修复后可运行代码如下:
# asamp_fixed.py import time import datetime import asyncio import websockets import threading def bgWorker_SK(): # 为当前子线程创建独立事件循环 loop = asyncio.new_event_loop() # 将事件循环绑定到当前线程 asyncio.set_event_loop(loop) # WebSocket连接处理逻辑 async def handler(websocket, path): data = await websocket.recv() reply = f"Data recieved as: {data}!" await websocket.send(reply) start_server = websockets.serve(handler, "localhost", 5564) # 用当前线程绑定的循环启动服务 loop.run_until_complete(start_server) loop.run_forever() # 启动后台WebSocket服务线程 threading.Thread(target=bgWorker_SK, daemon=True).start() if __name__ == '__main__': # 主线程原有逻辑不受任何影响 while True: print (datetime.datetime.now()) time.sleep(2)
关键说明
- asyncio事件循环非线程安全,禁止跨线程共享同一个事件循环,每个运行异步逻辑的线程必须创建、绑定自己的独立事件循环
- 服务启动后必须调用
loop.run_forever()保证事件循环持续驻留运行,才能持续监听端口的入站WebSocket请求 - 该方案完全不阻塞主线程的同步业务执行,适合原有同步代码占比高、不需要全量改造为异步架构的桌面应用场景
- 验证方法:代码启动后,使用任意WebSocket客户端连接
ws://localhost:5564发送测试消息,即可收到服务端响应,主线程的定时打印逻辑不会中断。
内容的提问来源于stack exchange,提问作者Scott B
相关产品推荐
相关产品推荐

