新线程运行async异步函数卡在asyncio.new_event_loop如何解决
问题根因
- 卡在
asyncio.new_event_loop()是跨线程创建事件循环的兼容性问题:- 主线程直接调用时,Python启动流程已经为主线程预初始化了适配当前系统的事件循环资源,不会触发资源申请死锁
- 子线程中直接创建事件循环时,Windows系统默认的
ProactorEventLoop会尝试申请仅主线程可访问的IOCP、信号处理相关资源,直接触发卡死;部分Linux环境下高版本websockets库提前绑定主线程事件循环钩子时,也会出现同类问题 - 原代码还存在两个隐性问题:一是
logger未定义,运行到异常分支会直接抛错;二是子线程设置为daemon=True,如果主线程启动子线程后没有阻塞逻辑,会直接退出杀死子线程,即使事件循环启动成功也无法持续运行
修复方法
在子线程入口函数最开头,手动指定适配子线程运行的事件循环策略,补全缺失的依赖,同时给主线程加阻塞等待逻辑:
import asyncio import json import threading import time import logging import websockets.client import websockets.exceptions # 补全logger配置 logging.basicConfig(level=logging.WARNING) logger = logging.getLogger(__name__) ws_url = "wss://phemex.com/ws/" sub_orderbook = {"id": 1234, "method": "orderbook.subscribe", "params": ["BTCUSD"]} async def orderbook(): while True: try: async for websocket in websockets.client.connect(ws_url, close_timeout=0.001): try: await websocket.send(json.dumps(sub_orderbook)) while True: msg = await websocket.recv() print(msg) obj = json.loads(msg) if isinstance(obj, dict) and obj.get('event') == 'ping': await websocket.send(json.dumps({'event': 'pong'})) except websockets.exceptions.ConnectionClosed as cc: logger.warning(f'Connection at {ws_url} closed: {cc}') continue except Exception: logger.warning(f'Restarting after unexpected exception:', exc_info=True) def orderbook_callback(): import sys # 子线程启动前先设置适配跨线程运行的事件循环策略 if sys.platform == 'win32': asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) print("Hi") loop = asyncio.new_event_loop() print("bye") asyncio.set_event_loop(loop) try: loop.run_until_complete(orderbook()) finally: loop.close() _thread = threading.Thread(target=orderbook_callback, daemon=True) _thread.start() # 主线程加阻塞,避免直接退出 while True: time.sleep(3600)
验证说明
- 运行后会先打印
Hi再打印bye,随后正常输出websocket返回的订单簿数据 - 如果是非Windows环境,不需要额外设置事件循环策略,只要补全logger配置和主线程阻塞逻辑即可正常运行
内容的提问来源于stack exchange,提问作者siad houssam
相关产品推荐
相关产品推荐

