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

FastAPI中async def与def对比:为何阻塞I/O操作不推荐使用async def

FastAPI阻塞I/O操作不推荐使用async def的核心原因

1. 事件循环的运行机制限制

FastAPI的异步路由运行在单线程的事件循环之上,这个模式的核心规则是:

  • 同一时间事件循环只能处理一个任务,只有当前任务主动通过await让出执行权时,事件循环才会调度执行其他待处理的任务
  • 阻塞I/O操作(比如同步HTTP请求requests.get()、同步文件读写、time.sleep()、同步数据库查询等)不会主动让出执行权,会直接占用整个事件循环直到操作完成
  • 一旦async def定义的路由中出现阻塞I/O,在阻塞的整个时间段内,服务所有的异步接口、后台异步任务都会被卡住,没有任何新请求能被处理,等同于服务临时假死

2. FastAPI对不同定义方式的路由的调度差异

FastAPI对def和async def定义的路由有完全不同的调度逻辑:

  • 如果你用普通def定义路由,FastAPI会自动将函数提交到独立的线程池中运行,阻塞操作只会阻塞当前所属的单个线程,不会影响事件循环的正常调度,其他请求依然可以被正常处理
  • 如果你用async def定义路由,FastAPI会直接将函数放到事件循环中执行,不会额外分配线程资源,此时函数内部的所有阻塞操作都会直接卡断整个事件循环的调度

3. 适用场景边界澄清

并不是说async def不能使用,而是只有满足以下所有条件时才适合用async def定义路由:

  • 路由内部的所有I/O操作均为异步非阻塞实现
  • 所有异步操作都添加了await关键字主动让出执行权
    比如使用httpx.AsyncClient做异步网络请求、aiopg做异步PostgreSQL查询、用asyncio.sleep替代time.sleep,这类场景下使用async def才能获得高并发收益
    如果你的代码中包含无法改造为异步实现的同步阻塞逻辑,直接用普通def定义路由即可,FastAPI内置的线程池调度已经做了充分优化,性能远高于硬写async def加阻塞操作的实现,且稳定性更高。

示例对比

错误用法:async def中加入阻塞I/O

import time
from fastapi import FastAPI

app = FastAPI()

@app.get("/block-test")
async def block_test():
    # 同步sleep会卡死事件循环10秒,期间所有请求都无法响应
    time.sleep(10)
    return {"status": "done"}

正确用法1:用普通def封装同步阻塞逻辑

import time
from fastapi import FastAPI

app = FastAPI()

@app.get("/sync-test")
def sync_test():
    time.sleep(10)
    return {"status": "done"}

正确用法2:async def搭配异步非阻塞操作

import asyncio
from fastapi import FastAPI

app = FastAPI()

@app.get("/async-test")
async def async_test():
    # 异步sleep会主动让出执行权,不影响其他请求处理
    await asyncio.sleep(10)
    return {"status": "done"}

内容的提问来源于stack exchange,提问作者Diogo Crava

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 08:21:02