Python 异步编程:Asyncio 实现原理

常见的并发模型

  • 多进程/多线程
  • 异步
  • Actor
  • Pub/Sub
    在这里插入图片描述

Python 异步的基石:协程

协程简介

概念:协作式多任务的子程序,用户态线程或微线程(Coroutine)。
特点:子程序执行可以中断,恢复后不会丢失之前的上下文状态。
区别:与线程不同,协程是用户级的非抢占式调度,比线程更轻量(纳秒级的 CPU 时间),无资源竞争,无需加锁。
Python 使用协程 + IO 多路复用实现异步编程。

Python 协程的发展历程

  • PEP 255 (Python 2.2):引入生成器,实现可迭代对象的惰性求值。
  • PEP 342:引入 sendthrow 方法,允许在 try/finally 中使用 yield
  • PEP 380 (Python 3.3):引入 yield from,简化生成器/协程的实现和串联。
  • PEP 3156 (Python 3.4):试验性引入异步 I/O 框架 asyncio。
  • PEP 492 (Python 3.5):通过 async/await 语法明确支持协程。
  • Python 3.6asyncio 成为标准库的一部分。

Python 第三方异步 I/O 方案

  • Greenlet
  • Gevent
  • Eventlet
  • Twisted

官方异步模块 Asyncio

认识几个概念

  • Task:协程的高层抽象。
  • Future:沟通协程和事件循环。
  • Coroutine:协程与 await 搭配使用的语法糖。
  • Event Loop:事件循环协程的执行调度。

从一个爬虫例子着手

阻塞方式写法
import socket
def blocking_run():sock = socket.socket()sock.connect(("example.com", 80))request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"sock.send(request.encode())response = sock.recv(2048)return response
for _ in range(10):print(blocking_run())
非阻塞方式 - 事件循环 + 回调
import socket
from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector
selector = DefaultSelector()
def no_blocking_run():def on_connect(key, mask):selector.unregister(key.fd)request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"sock.send(request.encode())selector.register(key.fd, EVENT_READ, on_response)return "on_connect success"def on_response(key, mask):response = sock.recv(2048)selector.unregister(key.fd)return "on_response success"sock = socket.socket()sock.setblocking(False)try:sock.connect(("example.com", 80))except BlockingIOError:passselector.register(sock.fileno(), EVENT_WRITE, on_connect)
def event_loop():for _ in range(10):no_blocking_run()while True:events = selector.select(timeout=3)if not events:breakfor event_key, event_mask in events:callback = event_key.dataprint(callback(event_key, event_mask))
执行过程说明
  1. 启动执行函数,创建 socket 连接并在 selector 上注册可写事件,无阻塞操作,函数立即返回。
  2. 遍历 10 个不同的下载任务,注册连接事件。
  3. 启动事件循环,阻塞在事件监听上。
  4. 当某个下载任务 EVENT_WRITE 被触发,回调其 on_connect 方法。
  5. 进入下一轮事件循环,处理事件。
回调地狱问题
  • 回调函数执行不正常时,错误处理困难。
  • 嵌套回调导致代码复杂。
  • 状态共享和管理困难。
callback_a(callback_b(callback_c(callback_d(...))))

对比基于协程的解决方案

Future 对象

作为数据接收代理,和系统事件沟通的桥梁

class Future:def __init__(self):self.result = Noneself._callbacks = []def add_done_callback(self, func):self._callbacks.append(func)def set_result(self, result):self.result = resultfor func in self._callbacks:func(self)
基于协程重构
def no_blocking_v2():sock = socket.socket()sock.setblocking(False)try:sock.connect(("example.com", 80))except BlockingIOError:passf = Future()selector.register(sock.fileno(), EVENT_WRITE, lambda: f.set_result(None))yield fselector.unregister(sock.fileno())request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"sock.send(request.encode())f = Future()selector.register(sock.fileno(), EVENT_READ, lambda: f.set_result(sock.recv(2048)))yield fselector.unregister(sock.fileno())
Task 对象

协程高层抽象,能管理和控制协程

class Task:def __init__(self, coro):self.coro = corof = Future()f.set_result(None)self.next(f)def next(self, future):try:next_future = self.coro.send(future.result)except StopIteration:returnnext_future.add_done_callback(self.next)
加入 Event Loop 驱动协程运行
def event_loop_v2():for _ in range(10):Task(no_blocking_v2())while True:events = selector.select(timeout=3)if not events:breakfor event_key, event_mask in events:callback = event_key.datacallback()

整个过程如图所示
在这里插入图片描述

协程风格与回调风格对比

  • 回调风格
    • 存在链式回调,破坏同步代码结构。
    • 需要在回调之间维护状态。
  • 协程风格
    • 无链式调用。
    • Selector 的回调只需设置 future 的值。
    • 事件循环只管调度,结构更接近同步代码。
    • 无需在多个协程之间维护状态。

结语

上述只是原型的简单介绍,实际 Asyncio 远比上述原型复杂,需要实现零拷贝、公平调度、异常处理、任务状态管理等。理解原理有助于在后续开发中更好地处理异步问题。

如果你对异步编程感兴趣,欢迎体验 AppBoot 项目,它基于FastAPI提供了一个类似 Django 的开发体验,完全异步,并内置 SQLAlchemy 2.0 支持。使用 AppBoot,你可以轻松快速地开发企业级的异步 Web 服务,感受异步编程的强大与乐趣。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生物反应器对Organoids培养有啥帮助?有几种?快来看看!

Bioreactor Technologies for Enhanced Organoid Culture是《INTERNATIONAL JOURNAL OF MOLECULAR SCIENCES》上的一篇文章,介绍了用于类器官培养的生物反应器,包括搅拌式、微流体、旋转壁容器和电刺激四类。搅拌式生物反应器通过改善氧合和实现适当的谱…

【iOS多线程(二)】GCD其他方法详解

GCD其他方法 dispatch_semaphore (信号量)什么是dispatch_semaphore(信号量)?dispatch_semaphore主要的三个方法dispatch_semaphore主要作用线程安全线程同步 dispatch_afterdispatch_time_t 两种形式 GCD 一次性代码(只执行一次&#xff09…

面向 RAG 应用开发者的实用指南和建议

向量搜索并非轻而易举! 向量搜索,也称为向量相似性搜索或最近邻搜索,是一种常见于 RAG 应用和信息检索系统中的数据检索技术,用于查找与给定查询向量相似或密切相关的数据。业内通常会宣传该技术在处理大型数据集时非常直观且简单…

【C语言】C语言期末突击/考研--结构体与C++引用

一、结构体--结构体对齐--结构体数组 1.1.结构体的定义、初始化、结构体数组 有时候需要将不同类型的数据组合为一一个整体,以便于引用。 例如,一名学生有学号、姓 名、性别、年龄、地址等属性,如果针对学生的学号、姓名、年龄等都单独定义一…

【MYSQL】表操作

目录 查看当前数据库含有表查看表结构创建表插入(新增create)查询(retrieve)全列查询指定列查询查询列是表达式别名查询(as)去重查询(distinct)排序查询(order by)条件查询(where)比较/逻辑运算符使用 分页查询(limit) 一条语句各…

【若依项目-RuoYi】掌握若依前端的基本流程

搞毕设项目,使用前后端分离技术,后端springBoot,前端vue3element plus。自己已经写好前端与后端代码,但想换一个前端界面所以使用到了若依,前前后后遇到许多坑,记录一下,方便之后能够快速回忆。…

尚硅谷谷粒商城项目笔记——八、安装node.js【电脑CPU:AMD】

八、安装node.js 注: [!NOTE] 查看本机系统 官网选择node.js版本 1傻瓜式安装,注意选择路径 图一 图二 至此,nodejs安装完成! 2环境配置 找到安装nodejs的路径新增 node_global 和node_cache文件夹 创建完两个空文件夹&#x…

如何快速入门 PyTorch ?

PyTorch是一个机器学习框架,主要依靠深度神经网络,目前已迅速成为机器学习领域中最可靠的框架之一。 PyTorch 的大部分基础代码源于 Ronan Collobert 等人 在 2007 年发起的 Torch7 项目,该项目源于 Yann LeCun 和 Leon Bottou 首创的编程语…

0207、创建场景状态的三个子类

VS使用的是3.5框架,会自带Linq这一行,Unity不支持,需要删除 一、创建三个场景 二、创建三个子类

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——5Webscoket节点的使用

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——5Webscoket节点的使用 ​ 有了前面几篇文章的铺垫,现在已经可以实现我到手测试那一步的 1.解读usb_websocket_display.launch.py ​ 首先进入这个目录/root/dev_ws/src/origincar/originca…

Java语言程序设计——篇十二

🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳&…

ChatGPT能代替网络作家吗?

最强AI视频生成:小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/ 当然可以!只要你玩写作AI玩得6,甚至可以达到某些大神的水平! 看看大神、小白、AI输出内容的区…

【枚举 图论】2242. 节点序列的最大得分

本文涉及知识点 枚举 图论知识汇总 LeetCode 2242. 节点序列的最大得分 给你一个 n 个节点的 无向图 ,节点编号为 0 到 n - 1 。 给你一个下标从 0 开始的整数数组 scores ,其中 scores[i] 是第 i 个节点的分数。同时给你一个二维整数数组 edges &…

logging日志实操入门

一、代码 import logging from logging.handlers import RotatingFileHandler # 配置日志 log_file_path ./logs/test.log file_handler RotatingFileHandler(log_file_path, maxBytes10, backupCount5)# 设置格式化器,以使日志更易读 formatter logging.Format…

Webstorm的下载与安装

Webstorm的下载 1 在浏览器的地址栏输入https://www.jetbrains.com/webstorm/,进入主页面 2 点击右上角的Download按钮,进入下载页面,如图所示 Webstorm的安装 按步骤逐步安装即可

SwiftUI 如何定制 Picker 视图当前选中行的背景颜色?

功能需求 有时我们希望可以定制 SwiftUI 中 Picker 视图当前选中行的背景色,这可以做到吗? 在上面的演示图中,我们随心所欲地变换着 SwiftUI 中 Picker 视图当前选中行的背景色。这是怎么做到的呢? 在本篇博文中,您将学到以下内容 功能需求1. 钩深极奥:修改 SwiftUI 原…

嵌入式学习之路 13(C语言基础学习——预处理命令)

编程流程 在进行程序开发时,通常遵循编辑源代码、编译、运行和调试这几个主要步骤。 编辑源代码:使用文本编辑器创建或修改程序的源代码,这是整个编程过程的起点。编译:将源代码转换为可执行文件的关键步骤。 预处理&#xff1a…

C#重要知识归纳总结

C#教程 C# 结构体(Struct) | 菜鸟教程C# 结构体(Struct) 在 C# 中,结构体(struct)是一种值类型(value type),用于组织和存储相关数据。 在 C# 中&#xff0c…

微服务-实现nacos的集群和Gateway网关的实现、认证校验、解决跨域

1. nacos的集群模式 1.1 分析 nacos在企业中的使用100%都是集群模式。需要掌握nacos集群的搭建 nacos的数据存放在derby本地磁盘中,nacos集群模式会导致数据库数据不一致,使用加一层思想,修改nacos的数据库,使用mysql数据库&…