You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在独立线程运行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:45:54