FastAPI学习-26 并发 async / await

news2024/11/16 1:21:36

前言

有关路径操作函数的 async def 语法以及异步代码、并发和并行的一些背景知识

async 和 await 关键字

如果你正在使用第三方库,它们会告诉你使用 await 关键字来调用它们,就像这样:

results = await some_library()

然后,通过 async def 声明你的 路径操作函数:

@app.get('/')
async def read_results():
    results = await some_library()
    return results

你只能在被 async def 创建的函数内使用 await

如果你正在使用一个第三方库和某些组件(比如:数据库、API、文件系统…)进行通信,第三方库又不支持使用 await (目前大多数数据库三方库都是这样),这种情况你可以像平常那样使用 def 声明一个路径操作函数,就像这样:

@app.get('/')
def results():
    results = some_library()
    return results

如果你的应用程序不需要与其他任何东西通信而等待其响应,请使用 async def

如果你不清楚,使用 def 就好.
注意:你可以根据需要在路径操作函数中混合使用 def 和 async def,并使用最适合你的方式去定义每个函数。FastAPI 将为他们做正确的事情。
无论如何,在上述任何情况下,FastAPI 仍将异步工作,速度也非常快。
但是,通过遵循上述步骤,它将能够进行一些性能优化。

技术细节

Python 的现代版本支持通过一种叫"协程"——使用 async 和 await 语法的东西来写”异步代码“。
让我们在下面的部分中逐一介绍:

  • 异步代码
  • async 和 await
  • 协程

异步代码

异步代码仅仅意味着编程语言 💬 有办法告诉计算机/程序 🤖 在代码中的某个点,它 🤖 将不得不等待在某些地方完成一些事情。让我们假设一些事情被称为 "慢文件"📝.

所以,在等待"慢文件"📝完成的这段时间,计算机可以做一些其他工作。

然后计算机/程序 🤖 每次有机会都会回来,因为它又在等待,或者它 🤖 完成了当前所有的工作。而且它 🤖 将查看它等待的所有任务中是否有已经完成的,做它必须做的任何事情。

接下来,它 🤖 完成第一个任务(比如是我们的"慢文件"📝) 并继续与之相关的一切。

这个"等待其他事情"通常指的是一些相对较慢(与处理器和 RAM 存储器的速度相比)的 I/O 操作,比如说:

通过网络发送来自客户端的数据
客户端接收来自网络中的数据
磁盘中要由系统读取并提供给程序的文件的内容
程序提供给系统的要写入磁盘的内容
一个 API 的远程调用
一个数据库操作,直到完成
一个数据库查询,直到返回结果
等等.
这个执行的时间大多是在等待 I/O 操作,因此它们被叫做 “I/O 密集型” 操作。
它被称为"异步"的原因是因为计算机/程序不必与慢任务"同步",去等待任务完成的确切时刻,而在此期间不做任何事情直到能够获取任务结果才继续工作。
相反,作为一个"异步"系统,一旦完成,任务就可以排队等待一段时间(几微秒),等待计算机程序完成它要做的任何事情,然后回来获取结果并继续处理它们。
对于"同步"(与"异步"相反),他们通常也使用"顺序"一词,因为计算机程序在切换到另一个任务之前是按顺序执行所有步骤,即使这些步骤涉及到等待。

并发与汉堡

上述异步代码的思想有时也被称为“并发”,它不同于“并行”。
并发和并行都与“不同的事情或多或少同时发生”有关。
但是并发和并行之间的细节是完全不同的。
要了解差异,请想象以下关于汉堡的故事:

并发汉堡

你和你的恋人一起去快餐店,你排队在后面,收银员从你前面的人接单。😍

然后轮到你了,你为你的恋人和你选了两个非常豪华的汉堡。🍔🍔

收银员对厨房里的厨师说了一些话,让他们知道他们必须为你准备汉堡(尽管他们目前正在为之前的顾客准备汉堡)。

你付钱了。 💸
收银员给你轮到的号码。

当你在等待的时候,你和你的恋人一起去挑选一张桌子,然后你们坐下来聊了很长时间(因为汉堡很豪华,需要一些时间来准备)。
当你和你的恋人坐在桌子旁,等待汉堡的时候,你可以用这段时间来欣赏你的恋人是多么的棒、可爱和聪明✨😍✨。

在等待中和你的恋人交谈时,你会不时地查看柜台上显示的号码,看看是否已经轮到你了。
然后在某个时刻,终于轮到你了。你去柜台拿汉堡然后回到桌子上。

你们享用了汉堡,整个过程都很开心。✨

在那个故事里,假设你是计算机程序 🤖 。
当你在排队时,你只是闲着😴, 轮到你前不做任何事情(仅排队)。但排队很快,因为收银员只接订单(不准备订单),所以这一切都还好。
然后,当轮到你时,需要你做一些实际性的工作,比如查看菜单,决定你想要什么,让你的恋人选择,支付,检查你是否提供了正确的账单或卡,检查你的收费是否正确,检查订单是否有正确的项目,等等。
此时,即使你仍然没有汉堡,你和收银员的工作也"暂停"了⏸, 因为你必须等待一段时间 🕙 让你的汉堡做好。
但是,当你离开柜台并坐在桌子旁,在轮到你的号码前的这段时间,你可以将焦点切换到 🔀 你的恋人上,并做一些"工作"⏯ 🤓。你可以做一些非常"有成效"的事情,比如和你的恋人调情😍.
之后,收银员 💁 把号码显示在显示屏上,并说到 “汉堡做好了”,而当显示的号码是你的号码时,你不会立刻疯狂地跳起来。因为你知道没有人会偷你的汉堡,因为你有你的号码,而其他人又有他们自己的号码。
所以你要等待你的恋人完成故事(完成当前的工作⏯ /正在做的事🤓), 轻轻微笑,说你要吃汉堡⏸.
然后你去柜台🔀, 到现在初始任务已经完成⏯, 拿起汉堡,说声谢谢,然后把它们送到桌上。这就完成了与计数器交互的步骤/任务⏹. 这反过来又产生了一项新任务,即"吃汉堡"🔀 ⏯, 上一个"拿汉堡"的任务已经结束了⏹.

并行汉堡

现在让我们假设不是"并发汉堡",而是"并行汉堡"。
你和你的恋人一起去吃并行快餐。
你站在队伍中,同时是厨师的几个收银员(比方说8个)从前面的人那里接单。
你之前的每个人都在等待他们的汉堡准备好后才离开柜台,因为8名收银员都会在下一份订单前马上准备好汉堡。

然后,终于轮到你了,你为你的恋人和你订购了两个非常精美的汉堡。
你付钱了 💸。

收银员去厨房。
你站在柜台前 🕙等待着,这样就不会有人在你之前抢走你的汉堡,因为没有轮流的号码。

当你和你的恋人忙于不让任何人出现在你面前,并且在他们到来的时候拿走你的汉堡时,你无法关注到你的恋人。😞

这是"同步"的工作,你被迫与服务员/厨师 👨‍🍳"同步"。你在此必须等待 🕙 ,在收银员/厨师 👨‍🍳 完成汉堡并将它们交给你的确切时间到达之前一直等待,否则其他人可能会拿走它们。

你经过长时间的等待 🕙 ,收银员/厨师 👨‍🍳终于带着汉堡回到了柜台。

你拿着汉堡,和你的情人一起上桌。

你们仅仅是吃了它们,就结束了。⏹

没有太多的交谈或调情,因为大部分时间 🕙 都在柜台前等待😞。

在这个并行汉堡的场景中,你是一个计算机程序 🤖 且有两个处理器(你和你的恋人),都在等待 🕙 ,并投入他们的注意力 ⏯ 在柜台上等待了很长一段时间。

这家快餐店有 8 个处理器(收银员/厨师)。而并发汉堡店可能只有 2 个(一个收银员和一个厨师)。

但最终的体验仍然不是最好的。😞

这将是与汉堡的类似故事。🍔

一种更"贴近生活"的例子,想象一家银行。

直到最近,大多数银行都有多个出纳员 👨‍💼👨‍💼👨‍💼👨‍💼 还有一条长长排队队伍🕙🕙🕙🕙🕙🕙🕙🕙。

所有收银员都是一个接一个的在客户面前做完所有的工作👨‍💼⏯.

你必须经过 🕙 较长时间排队,否则你就没机会了。

你可不会想带你的恋人 😍 和你一起去银行办事🏦.

汉堡结论

在"你与恋人一起吃汉堡"的这个场景中,因为有很多人在等待🕙, 使用并发系统更有意义⏸🔀⏯.

大多数 Web 应用都是这样的。

你的服务器正在等待很多很多用户通过他们不太好的网络发送来的请求。

然后再次等待 🕙 响应回来。

这个"等待" 🕙 是以微秒为单位测量的,但总的来说,最后还是等待很久。

这就是为什么使用异步对于 Web API 很有意义的原因 ⏸🔀⏯。

这种异步机制正是 NodeJS 受到欢迎的原因(尽管 NodeJS 不是并行的),以及 Go 作为编程语言的优势所在。

这与 FastAPI 的性能水平相同。

您可以同时拥有并行性和异步性,您可以获得比大多数经过测试的 NodeJS 框架更高的性能,并且与 Go 不相上下, Go 是一种更接近于 C 的编译语言(全部归功于 Starlette)。

并发比并行好吗?

不!这不是故事的本意。
并发不同于并行。而是在需要大量等待的特定场景下效果更好。因此,在 Web 应用程序开发中,它通常比并行要好得多,但这并不意味着全部。
因此,为了平衡这一点,想象一下下面的短篇故事:
你必须打扫一个又大又脏的房子。
是的,这就是完整的故事。
在任何地方, 都不需要等待 🕙 ,只需要在房子的多个地方做着很多工作。
你可以像汉堡的例子那样轮流执行,先是客厅,然后是厨房,但因为你不需要等待 🕙 ,对于任何事情都是清洁,清洁,还是清洁,轮流不会影响任何事情。

无论是否轮流执行(并发),都需要相同的时间来完成,而你也会完成相同的工作量。

但在这种情况下,如果你能带上 8 名前收银员/厨师,现在是清洁工一起清扫,他们中的每一个人(加上你)都能占据房子的一个区域来清扫,你就可以在额外的帮助下并行的更快地完成所有工作。

在这个场景中,每个清洁工(包括您)都将是一个处理器,完成这个工作的一部分。

由于大多数执行时间是由实际工作(而不是等待)占用的,并且计算机中的工作是由 CPU 完成的,所以他们称这些问题为"CPU 密集型"。

CPU 密集型操作的常见示例是需要复杂的数学处理。

例如:

音频或图像处理;
计算机视觉: 一幅图像由数百万像素组成,每个像素有3种颜色值,处理通常需要同时对这些像素进行计算;
机器学习: 它通常需要大量的"矩阵"和"向量"乘法。想象一个包含数字的巨大电子表格,并同时将所有数字相乘;
深度学习: 这是机器学习的一个子领域,同样适用。只是没有一个数字的电子表格可以相乘,而是一个庞大的数字集合,在很多情况下,你需要使用一个特殊的处理器来构建和使用这些模型。

并发 + 并行: Web + 机器学习

使用 FastAPI,您可以利用 Web 开发中常见的并发机制的优势(NodeJS 的主要吸引力)。

并且,您也可以利用并行和多进程(让多个进程并行运行)的优点来处理与机器学习系统中类似的 CPU 密集型 工作。

这一点,再加上 Python 是数据科学、机器学习(尤其是深度学习)的主要语言这一简单事实,使得 FastAPI 与数据科学/机器学习 Web API 和应用程序(以及其他许多应用程序)非常匹配。

了解如何在生产环境中实现这种并行性,可查看此文 Deployment

async 和 await

现代版本的 Python 有一种非常直观的方式来定义异步代码。这使它看起来就像正常的"顺序"代码,并在适当的时候"等待"。

当有一个操作需要等待才能给出结果,且支持这个新的 Python 特性时,您可以编写如下代码:

burgers = await get_burgers(2)

这里的关键是 await。它告诉 Python 它必须等待 ⏸ get_burgers(2) 完成它的工作 🕙 ,然后将结果存储在 burgers 中。这样,Python 就会知道此时它可以去做其他事情 🔀 ⏯ (比如接收另一个请求)。

要使 await 工作,它必须位于支持这种异步机制的函数内。因此,只需使用 async def 声明它:

    # Do some asynchronous stuff to create the burgers
    return burgers

…而不是 def:

# This is not asynchronous
def get_sequential_burgers(number: int):
    # Do some sequential stuff to create the burgers
    return burgers

使用 async def,Python 就知道在该函数中,它将遇上 await,并且它可以"暂停" ⏸ 执行该函数,直至执行其他操作 🔀 后回来。

当你想调用一个 async def 函数时,你必须"等待"它。因此,这不会起作用:

# This won't work, because get_burgers was defined with: async def
burgers = get_burgers(2)

因此,如果您使用的库告诉您可以使用 await 调用它,则需要使用 async def 创建路径操作函数 ,如:

@app.get('/burgers')
async def read_burgers():
    burgers = await get_burgers(2)
    return burgers

更多技术细节

您可能已经注意到,await 只能在 async def 定义的函数内部使用。
但与此同时,必须"等待"通过 async def 定义的函数。因此,带 async def 的函数也只能在 async def 定义的函数内部调用。
那么,这关于先有鸡还是先有蛋的问题,如何调用第一个 async 函数?
如果您使用 FastAPI,你不必担心这一点,因为"第一个"函数将是你的路径操作函数,FastAPI 将知道如何做正确的事情。
但如果您想在没有 FastAPI 的情况下使用 async / await,则可以这样做。
编写自己的异步代码
Starlette (和 FastAPI) 是基于 AnyIO 实现的,这使得它们可以兼容 Python 的标准库 asyncio 和 Trio。
特别是,你可以直接使用 AnyIO 来处理高级的并发用例,这些用例需要在自己的代码中使用更高级的模式。
即使您没有使用 FastAPI,您也可以使用 AnyIO 编写自己的异步程序,使其拥有较高的兼容性并获得一些好处(例如, 结构化并发)。

其他形式的异步代码
这种使用 async 和 await 的风格在语言中相对较新。
但它使处理异步代码变得容易很多。
这种相同的语法(或几乎相同)最近也包含在现代版本的 JavaScript 中(在浏览器和 NodeJS 中)。
但在此之前,处理异步代码非常复杂和困难。
在以前版本的 Python,你可以使用多线程或者 Gevent。但代码的理解、调试和思考都要复杂许多。
在以前版本的 NodeJS / 浏览器 JavaScript 中,你会使用"回调",因此也可能导致回调地狱。

协程

协程只是 async def 函数返回的一个非常奇特的东西的称呼。Python 知道它有点像一个函数,它可以启动,也会在某个时刻结束,而且它可能会在内部暂停 ⏸ ,只要内部有一个 await。
通过使用 async 和 await 的异步代码的所有功能大多数被概括为"协程"。它可以与 Go 的主要关键特性 “Goroutines” 相媲美。

原文https://fastapi.tiangolo.com/zh/async/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1084880.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

竞赛 深度学习 机器视觉 人脸识别系统 - opencv python

文章目录 0 前言1 机器学习-人脸识别过程人脸检测人脸对其人脸特征向量化人脸识别 2 深度学习-人脸识别过程人脸检测人脸识别Metric Larning 3 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习 机器视觉 人脸识别系统 该项目…

JVM第三讲:JVM 基础-字节码的增强技术详解

JVM 基础-字节码的增强技术详解 本文是JVM第三讲,JVM 基础-字节码的增强技术。在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术…

CV计算机视觉每日开源代码Paper with code速览-2023.10.12

精华置顶 墙裂推荐!小白如何1个月系统学习CV核心知识:链接 点击CV计算机视觉,关注更多CV干货 论文已打包,点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【目标检测】A Novel Voronoi-based Convolutional Neura…

二叉树题目:二叉树寻路

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题:二叉树寻路 出处:1104. 二叉树寻路 难度 5 级 题目描述 要求 在一个无限的二叉树上,每个结点都有两个子结点,结…

logicFlow 流程图编辑工具使用及开源地址

一、工具介绍 LogicFlow 是一款流程图编辑框架,提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow 支持前端研发自定义开发各种逻辑编排场景,如流程图、ER 图、BPMN 流程等。在工作审批配置、机器人逻辑编排、无…

玩转Linux Shell Terminal Tmux

一、Shell编程☘️ 1. Shell指令快捷操作 1. echo # 系统指令 $ echo $(pwd) # 对于系统自带的pwd,此处不能写echo $pwd# 自定义变量 $ foo$(pwd) $ echo $foo # 不同于pwd,对于自定义的foo,不能用$(foo)2. !! # 假设你先执行了以下原本…

JOSEF约瑟 矿用一般型选择性漏电继电器 LXY2-660 Φ45 JKY1-660

系列型号: JY82A检漏继电器 JY82B检漏继电器 JY82-380/660检漏继电器 JY82-IV检漏继电器 JY82-2P检漏继电器 JY82-2/3检漏继电器 JJKY检漏继电器 JD型检漏继电器 JY82-IV;JY82J JY82-II;JY82-III JY82-1P;JY82-2PA;JY82-2PB JJB-380;JJB-380/660 JD-12…

Generics/泛型, ViewBuilder/视图构造器 的使用

1. Generics 泛型的定义及使用 1.1 创建使用泛型的实例 GenericsBootcamp.swift import SwiftUIstruct StringModel {let info: String?func removeInfo() -> StringModel{StringModel(info: nil)} }struct BoolModel {let info: Bool?func removeInfo() -> BoolModel…

解析Moonbeam的安全性、互操作性和市场竞争力

Moonbeam依托Polkadot Substrate框架构建,用Rust程序设计语言创建的智能合约区块链平台,在继承Polkadot安全性的基础上为项目提供以太坊虚拟机(EVM)的兼容性和原生的跨链互操作性优势。Moonbeam的EVM兼容性表示开发者无需学习Subs…

LeetCode-102-二叉树的层序遍历

题目描述: 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 题目链接:LeetCode-102-二叉树的层序遍历 解题思路: 使用队列 先进先出的特点存储每次遍…

spring 通过有参构造方法注入

1.先写一个有参构造方法 2.给构造方法里面的属性 name 赋值 lisi 3.测试

[ROS2系列] ubuntu 20.04测试rtabmap 3D建图(二)

接上文我们继续 如果我们要在仿真环境中进行测试&#xff0c;需要将摄像头配置成功。 一、配置位置 sudo vim /opt/ros/foxy/share/turtlebot3_gazebo/models/turtlebot3_waffle/model.sdf 二、修改 <joint name"camera_rgb_optical_joint" type"fixed&…

【数据库】Sql Server数据迁移,处理自增字段赋值

给自己一个目标&#xff0c;然后坚持一段时间&#xff0c;总会有收获和感悟&#xff01; 在实际项目开发中&#xff0c;如果遇到高版本导入到低版本&#xff0c;或者低版本转高版本&#xff0c;那么就会出现版本不兼容无法导入&#xff0c;此时通过程序遍历创建表和添加数据方式…

CRMEB多商户商城系统阿里云集群部署教程

注意: 1.所有服务创建时地域一定要选择一致,这里我用的是杭州K区 2.文件/图片上传一定要用类似oss的云文件服务, 本文不做演示 一、 创建容器镜像服务&#xff0c;容器镜像服务(aliyun.com) ,个人版本就可以 先创建一个命名空间 然后创建一个镜像仓库 查看并记录镜像公网地址…

Flink之窗口聚合算子

1.窗口聚合算子 在Flink中窗口聚合算子主要分类两类 滚动聚合算子(增量聚合)全窗口聚合算子(全量聚合) 1.1 滚动聚合算子 滚动聚合算子一次只处理一条数据,通过算子中的累加器对聚合结果进行更新,当窗口触发时再从累加器中取结果数据,一般使用算子如下: aggregatemaxmaxBy…

Unity中Shader光照模型Phong

文章目录 前言一、Phong光照模型二、图示解释Phone光照模型1、由图可得&#xff0c;R 可以由 -L 加上 P 得出2、P等于2*M3、因为 N 和 L 均为单位向量&#xff0c;所以 M 的模可以由 N 和 L得出4、得到M的模后&#xff0c;乘以 单位向量N&#xff0c;得到M5、最后得出 P 和 R 前…

Prometheus-Prometheus安装及其配置

Prometheus-Prometheus安装及其配置 Prometheus安装下载解压 配置启动prometheus校验配置文件表达式浏览器 Prometheus安装 Prometheus的安装针对Linux的安装&#xff0c;其他的安装方式可以查看Prometheus官网 下载 sudo wget https://github.com/prometheus/prometheus/re…

四款数字办公工具大比拼,在线办公无压力

在线办公软件使企业、员工实现办公场所、距离的自由&#xff0c;尤其是近几年&#xff0c;受“口罩”的影响&#xff0c;远程办公软件的使用者也越来越多&#xff0c;无论是财务、行政、还是设计师&#xff0c;都开始追求好用的在线办公软件&#xff0c;作为办公软件发烧友&…

发送消息时序图

内窥镜消息队列发送消息原理 目的 有一个多线程的Java应用程序&#xff0c;使用消息队列来处理命令 时序图 startumlactor User participant "sendCmdWhiteBalance()" as Controller participant CommandConsumer participant MessageQueueUser -> Controller:…

​左手 Serverless,右手 AI,7 年躬身的古籍修复之路

作者&#xff1a;宋杰 “AI 可以把我们思维体系当中&#xff0c;过度专业化、过度细分的这些所谓的知识都替代掉&#xff0c;让我们集中精力去体验自己的生命。我挺幸运的&#xff0c;代码能够有 AI 辅助&#xff0c;也能够有 Serverless 解决我的运营成本问题。Serverless 它…