FastAPI到底用不用async?

本文通过实验对比了FastAPI框架中不同模式下函数的执行效率。揭示了在使用async模式时,若函数体内未合理使用await,则会导致串行执行的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FastAPI的很快,归功于它的异步处理。

那我们用FastAPI框架时,函数到底用不用async模式?

 

官方文档:

https://fastapi.tiangolo.com/async/

 

做个实验:

from fastapi import APIRouter
import time
import asyncio

router = APIRouter()


@router.get("/a")
async def a():
    time.sleep(1)
    return {"message": "异步模式,但是同步执行sleep函数,执行过程是串行的"}


@router.get("/b")
async def b():
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, time.sleep, 1)
    return {"message": "线程池中运行sleep函数"}


@router.get("/c")
async def c():
    await asyncio.sleep(1)
    return {"message": "异步模式,且异步执行sleep函数"}


@router.get("/d")
def d():
    time.sleep(1)
    return {"message": "同步模式,但是FastAPI会放在线程池中运行,所以很快"}

我们并发100个请求分别测试这4个接口。

 

结果:

/a接口:100秒

/b接口:1秒

/c接口:1秒

/d接口:3秒

 


/a接口:

fastapi框架会将async函数会放到event loop中运行。

虽然使用了async,但是函数内部并没有用到await,所以堵塞了。

执行过程是串行的,所以总耗时100秒。

 

/b接口:
利用asyncio异步IO获取当前的event loop。

然后将time.sleep(1)放到一个event loop中去运行,函数内部用到了await,所以无堵塞。
执行过程是并行的,所以总耗时1秒。

 

/c接口:

使用异步IO的sleep取代了普通的同步sleep。
原理与/b接口一致。
执行过程是并行的,所以总耗时1秒。

 

/d接口:

这个函数没有async修饰,即一个普通函数。
但是FastAPI会将函数放到thread pool中执行。

服务器是8核CPU,线程池的默认配置是核心数*5=40。
服务器在第一秒和第二秒分别处理40个请求,第三秒处理20个请求。

所以100个并发总耗时3秒。

 

总结:

官方说,无论你是否使用async,FastAPI都会采用异步的方式处理。

但是,如果你定义了async函数,函数体却是同步的调用(例:/a接口),将导致函数执行过程变成串行。

 

FastAPI中实现依赖注入是该框架的核心特性之一。依赖注入允许开发者在路由处理函数中声明所需的依赖项,FastAPI会自动管理这些依赖项的创建和传递。下面是一个基本的依赖注入实现步骤: 1. 定义依赖:首先,你需要定义一个函数,这个函数将作为依赖项。你可以在这个函数中实现你需要的逻辑,比如数据库连接、身份验证等。 2. 使用依赖:在你的路由处理函数中,将定义好的依赖函数作为参数添加进去。FastAPI会自动解析这些依赖,并将它们作为参数传递给相应的路由处理函数。 3. 运行时处理:当一个请求被发送到路由时,FastAPI会首先运行依赖函数,获取依赖项,并将其传递给处理函数。 下面是一个简单的例子: ```python from fastapi import FastAPI from pydantic import BaseModel # 定义一个依赖项函数 def get_query_token(q: str = None): return q # 定义一个模型用于路径操作的请求体 class Item(BaseModel): name: str description: str = None price: float tax: float = None # 创建FastAPI实例 app = FastAPI() # 定义一个路由处理函数,并使用依赖项 @app.get("/items/") async def read_items(token: str = Depends(get_query_token)): return {"token": token} # 定义另一个依赖项,用于获取用户信息 async def get_current_user(token: str = Depends(get_query_token)): # 这里可以添加代码以获取当前用户的信息 return {"username": "current_user", "token": token} # 使用依赖项的路由处理函数 @app.get("/users/me") async def read_user_me(current_user: dict = Depends(get_current_user)): return current_user ``` 在这个例子中,`get_query_token` 是一个简单的依赖函数,用于从查询参数中获取token。在`read_items` 路由处理函数中,我们通过`Depends(get_query_token)`声明了这个依赖项,这意味着在调用`read_items`之前,`get_query_token`会被执行,并且其返回值会作为参数`token`传递给`read_items`。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值