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

为何用create_task+asyncio.run从同步函数启动的异步协程未执行完毕?

问题原因

你的代码里asyncio.run(background_task())执行完后,事件循环直接被关闭了,这是核心问题:

  • asyncio.run()的逻辑是:创建事件循环 → 运行传入的协程 → 等待该协程完全结束后立即关闭事件循环
  • background_task()里用asyncio.create_task(task())创建了后台任务,但它自己执行到print("b")就结束了,asyncio.run()随之关闭事件循环
  • task()执行到第一个await asyncio.sleep(1)时会让出控制权,这时候事件循环已经被关闭,所以后续的迭代代码根本没机会运行,只能输出第一次迭代的内容
解决方案

因为你是在大型同步应用里启动后台异步任务,核心需求是让异步任务和同步代码并行运行,所以需要把事件循环放到独立线程中持续运行,避免被asyncio.run()的关闭逻辑打断。

修改后的代码示例:

import asyncio
from time import sleep
import sys
import threading


async def task():
    for i in range(5):
        print(f"Background task iteration {i}")
        await asyncio.sleep(1)
    print('finished')


async def background_task():
    print("a")
    asyncio.create_task(task())
    print("b")


def main():
    print("Main program started python", sys.version)

    # 创建事件循环并在后台线程启动
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    # 用守护线程运行事件循环,主线程结束时自动退出
    threading.Thread(target=loop.run_forever, daemon=True).start()

    # 跨线程提交后台任务到事件循环
    asyncio.run_coroutine_threadsafe(background_task(), loop)

    # 同步业务逻辑
    for i in range(3):
        sleep(3)
        print(f"Main program iteration {i}")
    
    # 可选:如果同步代码结束后不需要异步任务继续运行,关闭事件循环
    loop.call_soon_threadsafe(loop.stop)


if __name__ == "__main__":
    main()
关键说明
  • 把事件循环放到后台线程用loop.run_forever()持续运行,不会被同步代码阻塞
  • 跨线程提交协程必须用asyncio.run_coroutine_threadsafe(),不能直接用asyncio.create_task()(后者只能在事件循环所在线程调用)
  • 守护线程(daemon=True)会在主线程结束时自动终止,避免程序无法退出

内容的提问来源于stack exchange,提问作者Mehdi Ben Hamida

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:57:37