当前位置: 首页 > news >正文

async 和 await

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

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

burgers = await get_burgers(2)

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

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

async def get_burgers(number: int): # 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 编写自己的异步程序,使其拥有较高的兼容性并获得一些好处(例如, 结构化并发)。

我(指原作者 —— 译者注)基于 AnyIO 新建了一个库,作为一个轻量级的封装层,用来优化类型注解,同时提供了更好的自动补全内联错误提示等功能。这个库还附带了一个友好的入门指南和教程,能帮助你理解并编写自己的异步代码:Asyncer。如果你有结合使用异步代码和常规(阻塞/同步)代码的需求,这个库会特别有用。

其他形式的异步代码

这种使用asyncawait的风格在语言中相对较新。

但它使处理异步代码变得容易很多。

这种相同的语法(或几乎相同)最近也包含在现代版本的 JavaScript 中(在浏览器和 NodeJS 中)。

但在此之前,处理异步代码非常复杂和困难。

在以前版本的 Python,你可以使用多线程或者 Gevent。但代码的理解、调试和思考都要复杂许多。

在以前版本的 NodeJS / 浏览器 JavaScript 中,你会使用"回调",因此也可能导致“回调地狱”。

协程

协程只是async def函数返回的一个非常奇特的东西的称呼。Python 知道它有点像一个函数,它可以启动,也会在某个时刻结束,而且它可能会在内部暂停 ⏸ ,只要内部有一个await

通过使用asyncawait的异步代码的所有功能大多数被概括为"协程"。它可以与 Go 的主要关键特性 "Goroutines" 相媲美。

结论

让我们再来回顾下上文所说的:

Python 的现代版本可以通过使用asyncawait语法创建协程,并用于支持异步代码

现在应该能明白其含义了。

所有这些使得 FastAPI(通过 Starlette)如此强大,也是它拥有如此令人印象深刻的性能的原因。

路径操作函数

当你使用def而不是async def来声明一个路径操作函数时,它运行在外部的线程池中并等待其结果,而不是直接调用(因为它会阻塞服务器)。

如果你使用过另一个不以上述方式工作的异步框架,并且你习惯于用普通的def定义普通的仅计算路径操作函数,以获得微小的性能增益(大约100纳秒),请注意,在 FastAPI 中,效果将完全相反。在这些情况下,最好使用async def,除非路径操作函数内使用执行阻塞 I/O 的代码。

在这两种情况下,与你之前的框架相比,FastAPI可能仍然很快。

依赖

这同样适用于依赖。如果一个依赖是标准的def函数而不是async def,它将被运行在外部线程池中。

子依赖

你可以拥有多个相互依赖的依赖以及子依赖 (作为函数的参数),它们中的一些可能是通过async def声明,也可能是通过def声明。它们仍然可以正常工作,这些通过def声明的函数将会在外部线程中调用(来自线程池),而不是"被等待"。

其他函数

你可直接调用通过defasync def创建的任何其他函数,FastAPI 不会影响你调用它们的方式。

这与 FastAPI 为你调用路径操作函数和依赖项的逻辑相反。

如果你的函数是通过def声明的,它将被直接调用(在代码中编写的地方),而不会在线程池中,如果这个函数通过async def声明,当在代码中调用时,你就应该使用await等待函数的结果。

http://www.jsqmd.com/news/101394/

相关文章:

  • YOLO模型部署到生产环境的最佳实践
  • Applite:重塑Mac软件管理新体验的智能工具
  • 构造函数例子
  • 超实用的“财务数据统计报表-可视化图表”Excel模板分享!
  • 基于STM32和FreeRTOS的智能家居设计之路
  • 告别 “烟囱式” 困局:数据库一体化承载破解资源浪费・运维复杂・扩展不足
  • Python自动化AutoCAD终极指南:pyautocad库高效解决方案
  • BBDown完全掌握:从零基础到高效下载B站视频的完整指南
  • Video DownloadHelper CoApp 浏览器视频下载增强工具完整配置指南
  • Unity游戏自动翻译终极解决方案:从问题识别到快速上手避坑指南
  • 针对AGV机器人、AMR及机器狗乘梯的需求,结合十几年项目经验,多奥为你整理了详细的电梯配合要求和实施注意事项。为了确保自动化设备能安全、稳定地使用电梯,你需要重点关注以下几个核心维度:
  • 5分钟搞定Android投屏:QtScrcpy零门槛操作指南
  • ThinkPad终极静音方案:TPFanCtrl2双风扇智能控制系统深度解析
  • 在现有App里嵌入一个AI协作者
  • 微信网页版访问快速解决方案:wechat-need-web插件完整指南
  • 微信公众号运营:如何持续输出LobeChat相关内容?
  • ros2话题通讯实践-系统检测可视化工具
  • 拿捏 React 组件通讯:从父子到跨组件的「传功秘籍」
  • 如何快速为OBS直播添加专业级VST音频效果:终极完整指南
  • tensorflow 零基础吃透:tf.sparse.SparseTensor 与核心 TensorFlow API 的协同使用
  • 入职宇树Web前端开发,30K双休有点爽
  • ORACLE学习笔记总结(数据库归档模式的配置)
  • Applite:告别命令行,用图形界面轻松管理macOS软件包
  • 3步搞定老旧Mac升级:OpenCore Legacy Patcher USB启动盘制作全攻略
  • ORACLE学习笔记总结(数据库常见错误及应对措施)
  • 小白进阶 “挖洞大神”:SRC 漏洞挖掘完整攻略(附工具包 + 系统学习路径)
  • tensorflow 零基础吃透:TensorFlow 张量切片与数据插入(附目标检测 / NLP 实战场景)
  • WebPlotDigitizer:科研图表数据提取的终极完整指南
  • ThinkPad双风扇终极静音指南:TPFanCtrl2完整配置与优化
  • 微信网页版终极解决方案:wechat-need-web插件一键突破访问限制