如何在同一事件循环下于不同线程运行协程并获取返回结果
在主线程事件循环中开启新线程运行协程并获取结果
之前代码的问题分析
- 第一段代码中,
while not task.done()会阻塞主线程的事件循环,导致io_task永远无法被调度执行,最终程序挂起——事件循环被死循环占用,无法处理异步任务的切换。 - 第二段代码仅将Future对象存入列表,未等待其完成并获取结果,且调用逻辑未正确衔接主线程事件循环。
方式一:新线程启动独立事件循环执行协程
适合无需依赖主线程事件循环的场景,直接在新线程内运行协程并同步获取结果:
import asyncio from threading import Thread class Main: def __init__(self, result_from_io_task=None): self._io_task_result = result_from_io_task async def io_task(self): await asyncio.sleep(2) return "slept for 2s" def non_async_func(self): if not self._io_task_result: def run_coro_in_thread(): # 在新线程启动独立事件循环并运行协程 result = asyncio.run(self.io_task()) self._io_task_result = result thr = Thread(target=run_coro_in_thread) thr.start() thr.join() # 等待线程完成,确保结果已存入 return self._io_task_result # 测试执行 if __name__ == "__main__": main_obj = Main() print(main_obj.non_async_func()) # 输出: slept for 2s
方式二:复用主线程事件循环,线程安全提交协程
如果需要复用主线程的事件循环,可使用asyncio.run_coroutine_threadsafe将协程提交到主线程循环执行,同步获取结果:
import asyncio from threading import Thread class Main: def __init__(self, result_from_io_task=None): self._io_task_result = result_from_io_task async def io_task(self): await asyncio.sleep(2) return "slept for 2s" def non_async_func(self, main_loop): if not self._io_task_result: # 将协程提交到主线程的事件循环 thread_safe_fut = asyncio.run_coroutine_threadsafe(self.io_task(), main_loop) # 同步等待结果,此操作不会阻塞主线程事件循环 self._io_task_result = thread_safe_fut.result() return self._io_task_result async def main(): main_loop = asyncio.get_running_loop() main_obj = Main() # 用asyncio.to_thread将非异步函数放到新线程执行,避免阻塞主线程循环 result = await asyncio.to_thread(main_obj.non_async_func, main_loop) print(result) # 输出: slept for 2s if __name__ == "__main__": asyncio.run(main())
两种方式的差异
- 方式一:新线程独立运行事件循环,逻辑简单,无需依赖主线程循环,适合独立异步任务场景。
- 方式二:复用主线程事件循环,适合需要与主线程其他异步任务交互的场景,通过线程安全的Future对象完成跨线程任务调度。
内容的提问来源于stack exchange,提问作者user6037143
相关产品推荐
相关产品推荐

