Python中可否让websockets在后台运行并支持外部调用send方法
问题分析
你代码的核心问题有两个:
receive方法是无限循环,await handler.receive()会直接卡住整个Iao()协程,后续的send、close永远不会执行,同时loop.run_until_complete(Iao())会一直等待协程结束,导致后面的同步while循环完全无法运行- 后续你用
asyncio.run()调用send会创建全新的独立事件循环,和承载websocket连接的旧事件循环完全隔离,必然调用失败
解决代码
不需要额外创建新的顶层async函数,用子线程单独跑asyncio事件循环即可实现需求,修改后代码如下:
import asyncio import websockets import time import threading class WebsocketHandler(): def __init__(self): self.conn = None self.loop = None async def connect(self, url): self.conn = await websockets.connect(url) # 将receive作为后台任务运行,不阻塞当前协程 asyncio.create_task(self.receive()) async def send(self, msg): await self.conn.send(msg) async def receive(self): while True: print(await self.conn.recv()) async def close(self): await self.conn.close() async def Iao(): global handler handler = WebsocketHandler() await handler.connect('ws://localhost:8765') # 保持协程运行不退出即可 while True: await asyncio.sleep(3600) # 子线程运行事件循环的函数 def run_loop(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) handler.loop = loop loop.run_until_complete(Iao()) # 初始化handler并启动子线程跑事件循环 handler = None threading.Thread(target=run_loop, daemon=True).start() # 等待连接完成,可自行替换为更优雅的事件通知逻辑 time.sleep(1) while True: print("1") # 跨线程提交协程任务到子线程的事件循环执行 asyncio.run_coroutine_threadsafe(handler.send('{"action":"plus"}'), handler.loop).result() print("2") time.sleep(2)
核心说明
- 单独启动子线程运行asyncio事件循环,不会阻塞主线程的同步业务逻辑
- 连接完成后用
asyncio.create_task()将receive转为后台任务,不会阻塞后续逻辑执行,同时可以持续监听消息并打印 - 主线程要调用异步send方法时,使用
asyncio.run_coroutine_threadsafe将协程提交到子线程的事件队列中,实现跨线程安全调用异步方法,满足其他函数调用send发消息的需求
内容的提问来源于stack exchange,提问作者vogel
相关产品推荐
相关产品推荐

