在独立线程运行asyncio事件循环,如何正确获取协程执行结果?
异步API类调用问题解决方案
问题场景
对接经纪商复杂API时,需要实现一个可实例化的内部API类,要求启动asyncio事件循环在独立线程运行,避免阻塞程序其他部分,支持WebSocket长连接、订单操作等交互。但当前调用download_all()返回的是协程对象,而非预期的整数列表。
原代码
import asyncio import random import threading class Api: def __init__(self): self.loop = asyncio.get_event_loop() self.start_loop() def start_loop(self): thr = threading.Thread(target=self.loop.run_forever, daemon=True) thr.start() async def get_data(self): await asyncio.sleep(1) return random.randint(1, 10) async def download_data(self): results = [] for i in range(3): task = asyncio.ensure_future(self.get_data(), loop=self.loop) res = await task results.append(res) return results def download_all(self): result = self.download_data() return result if __name__ == '__main__': a = Api() results = a.download_all()
问题原因
download_data()是异步函数,直接调用只会返回协程对象,不会自动执行。由于事件循环运行在独立线程,必须用asyncio提供的线程安全方法提交协程并等待结果。
修改后的代码
import asyncio import random import threading class Api: def __init__(self): self.loop = asyncio.new_event_loop() # 创建独立事件循环,避免和主线程循环冲突 self.start_loop() def start_loop(self): thr = threading.Thread(target=self.loop.run_forever, daemon=True) thr.start() async def get_data(self): await asyncio.sleep(1) return random.randint(1, 10) async def download_data(self): # 用gather实现并发执行,提升效率 tasks = [self.get_data() for _ in range(3)] results = await asyncio.gather(*tasks) return results def download_all(self): # 线程安全地提交协程到独立事件循环,等待结果返回 future = asyncio.run_coroutine_threadsafe(self.download_data(), self.loop) return future.result() if __name__ == '__main__': a = Api() results = a.download_all() print(results) # 输出类似[5, 2, 9]的整数列表
关键修改说明
- 初始化时改用
asyncio.new_event_loop()创建独立事件循环,避免与主线程默认循环产生冲突 download_data()中用asyncio.gather()替代逐个await,让多个get_data()并发执行,提升运行效率download_all()中使用asyncio.run_coroutine_threadsafe(),这是线程安全的方法,可将协程提交到独立线程的事件循环中,并通过future.result()等待执行完成后获取最终结果
内容的提问来源于stack exchange,提问作者jacksonwoody
相关产品推荐
相关产品推荐

