Fastapi系列-同步和异步相互转换处理实践

本文介绍了在FastAPI中同步和异步函数相互转换的实践,包括`run_in_executor`、`asyncio.run_coroutine_threadsafe`和`asyncio.to_thread`等工具的使用。通过asgiref库实现异步到同步和同步到异步的转换,同时讨论了转换过程中的性能损耗和线程安全问题。并展示了多个转换库的实际应用,如BackgroundTasks、asyncer、awaits和aioify。

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

前言

我们知道Fastapi本身是一个混搭的框架,它既可以使用同步的方式也可以使用的异步的方式来运行我们的服务。

  • 同步的方式主要是使用多线程的方式来实现并发
  • 异步的方式则主要是基于协程的方式来实现并发

混搭的框架中主要遇到的问题点有:

  • 在同步函数里面如果有涉及到调用异步的函数(或协程对象的)
  • 在异步的函数里如果遇到的同步的代码(耗时的会引发阻塞的或部分的库不支持异步协程的)

以上两种场景情况都需要我们进行处理转化。

基础知识点

1 转换的说明

不管是从同步到异步,还是异步到同步,他们涉及的问题相对复杂,甚至转化过程其实会有相关的性能损耗,因为在转换处理中,我们需要考虑的是线程安全或协程安全等问题。

  • 同步到异步的转化:

    • 问题处理过程是需要把同步运行的代码丢进一个额外的线程池里面去执行,为避免拥堵阻塞,并且在单独线程执行完成我们的同步函数的逻辑处理之后需要把结果返回异步协程中。
  • 异步到同步的转化:

    • 问题处理过程是需要在把在运行在主线程上的是协程函数的调用转化为一个在子线程中运行的普通函数,并在异步函数处理完成的逻辑之后返回到同步运行的子线程中。

2 涉及一些函数

2.1 run_in_executor(同步到异步)

  • 用于在异步函数中(被async修饰的异步函数)里面,调用同步函数(如果此时同步函数是阻塞的话,那么有可能引起整个单线程模式的整个事件循环进行阻塞)的时候把同步函数的调用放到线程池里面进行执行,让其他任务也可以继续在事件循环中保持执行
  • 简而言之就是:一个是主线程,直接新开线程,运行阻塞函数

2.2 asyncio.run_coroutine_threadsafe(异步到同步)

  • 用于在同步函数里面调用协程对象的处理方案(非协程函数中不能使用await进行调用异步对象)。它最终的处理机制值:这个是将asyncio包的future对象转化返回一个concurrent.futures包的future对象。
  • 简而言之就是:动态的加入协程,参数为一个回调函数和一个loop对象,返回值为future对象,通过future.result()获取回调函数返回值

2.3 asyncio.to_thread

该函数的在py3.9版本中才提供的,它是对asyncio的操作多线程一种方案,使用它可以直接进行函数直接开线程。

转化处理实际案例

下面我们展开具体的案例来进行说明。

1、异步到同步的转化

这场景是比较场景的,比如:你需要的多线程的模式下读取对应提交过来的body的时候。由于本身Fastapi提供的reques.body()是一个协程函数,也就是需要使用awite reques.body()所以就遇到转换问题。

1.1 问题表现

@app.post("/get/access_token")
def access_token(reques:Request,name=Body(...)):
     print(reques.body())
    await reques.body()
    return 'pk' 

在上面中await reques.body()明显是会错,在普通函数里面嵌套使用await调用携程函数是不可以。所以我们需要进行转换。问题解决,引入django中提供一个关于转换包asgiref。这个包独立的,他可以独立安装。框架安装的时候本身其实就默认的自带安装asgiref。

1.2 asgiref包介绍

asgiref提供了两个非常方便的转换函数,

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值