• Jupyter 本身已经启动了 asyncio event loop
  • uvicorn.run() 内部会调用 asyncio.run()
  • 于是:
    loop 已存在 → uvicorn 再建 loop → 直接 RuntimeError

👉 这不是你代码的问题,是运行环境冲突

二、正确解决方案(按推荐顺序)

✅ 方案 1(强烈推荐):用 uvicorn.Server(Jupyter 官方解法)

这是唯一干净、可控、不 hack 的方式

import uvicorn
import asyncio

config = uvicorn.Config(
    app,
    host="0.0.0.0",
    port=port,
    log_level="info",
)

server = uvicorn.Server(config)

await server.serve()

📌 关键点:

  • 不要用 uvicorn.run()
  • 直接 await server.serve()
  • 完全兼容 Jupyter 的 event loop

✅ 方案 2:在后台线程启动 uvicorn(实用但稍脏)

import threading
import uvicorn

def run():
    uvicorn.run(app, host="0.0.0.0", port=port)

threading.Thread(target=run, daemon=True).start()

📌 适合:

  • 临时调试
  • 不想改 FastAPI 结构

⚠ 不适合:

  • 长期服务
  • 热重载
  • 精细生命周期控制

⚠ 方案 3:nest_asyncio(不推荐生产)

import nest_asyncio
nest_asyncio.apply()

import uvicorn
uvicorn.run(app, host="0.0.0.0", port=port)

📌 适合教学 / demo
🚫 不适合真实服务

三、你不该在 Jupyter 里做的事 ❌

uvicorn.run(app, ...)
asyncio.run(uvicorn.run(...))
asyncio.get_event_loop().run_until_complete(...)

👉 都是 反模式

四、最佳实践建议(经验总结)

✅ 开发期

  • Jupyter:只做

    • API 逻辑
    • 数据验证
    • 单元测试
  • 终端跑服务:

uvicorn main:app --reload --port 8000

✅ 如果你一定要 Notebook + 服务

👉 只用 Server + await serve()


五、最小可运行示例(FastAPI + Jupyter)

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
async def root():
    return {"msg": "hello"}

config = uvicorn.Config(app, host="0.0.0.0", port=8000)
server = uvicorn.Server(config)

await server.serve()
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐