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

uvicorn环境下asyncio.run报错及Pub/Sub订阅后台启动咨询

问题原因与解决方案

1. 为什么会出现RuntimeError?

你的判断完全正确——asyncio.run()的用法确实有误,而且Uvicorn已经在运行一个asyncio事件循环了:

  • asyncio.run()的核心作用是创建全新事件循环并运行协程,执行结束后还会关闭这个循环。
  • Uvicorn作为ASGI服务器,启动时就会初始化并持续运行一个事件循环,所有接口请求、异步任务都在这个循环里处理。
  • 在已有运行中的事件循环里调用asyncio.run(),必然触发“不能从运行中循环调用asyncio.run()”的冲突错误。

2. 如何在后台启动Pub/Sub订阅?

无需额外创建新循环,直接利用Uvicorn已有的事件循环,把订阅协程包装成后台任务即可,这样不会阻塞main.py的执行,控制权会立刻返回。

方案一:利用框架生命周期事件(推荐,如FastAPI/Starlette)

如果你的应用用了FastAPI这类支持生命周期事件的框架,直接在启动事件里创建后台任务:

import asyncio
from fastapi import FastAPI

app = FastAPI()

# 你的Pub/Sub订阅协程
async def create_bill_subscriber():
    # 初始化订阅者逻辑
    subscriber = # 这里写入你的Pub/Sub订阅者初始化代码
    async with subscriber:
        async for message in subscriber:
            # 处理消息的逻辑
            print(f"收到消息: {message.data}")
            message.ack()

# 在应用启动时触发后台任务
@app.on_event("startup")
async def start_subscriber():
    # 将订阅协程加入当前事件循环,后台异步执行
    asyncio.create_task(create_bill_subscriber())

方案二:直接获取当前事件循环添加任务

如果没有用框架的生命周期事件,确保在Uvicorn事件循环启动后执行以下代码:

import asyncio

# 你的Pub/Sub订阅协程
async def create_bill_subscriber():
    # ... 订阅逻辑 ...

# 适合用代码直接启动Uvicorn的场景
if __name__ == "__main__":
    import uvicorn
    loop = asyncio.get_event_loop()
    loop.create_task(create_bill_subscriber())
    uvicorn.run(app, host="0.0.0.0", port=8000)

关键注意事项

  • asyncio.create_task()会把协程放到当前事件循环的任务队列中,后台异步执行,不会阻塞主线程后续逻辑。
  • 不要在脚本最外层直接调用asyncio.create_task(),必须确保代码在Uvicorn的事件循环启动后执行(比如启动事件、代码启动Uvicorn前)。

内容的提问来源于stack exchange,提问作者Sumit Desai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 19:20:11