Python协程技术:从Greenlet到async/await的异步编程探索

协程:

​ 协程,在Python中,协程是一种轻量级的并发编程方式,它允许在单个线程内实现多个独立的执行流。协程可以在不同的执行点之间进行切换,而无需依赖于操作系统的线程切换。这使得协程成为处理高并发和异步任务的有力工具。

def func1():
	print(1)
    ...
	print(2)
	
def func2():
	print(3)
    ...
	print(4)

func1()
func2()

​ 上述代码是普通的函数定义和执行,按流程分别执行两个函数中的代码,并先后会输出:1、2、3、4。但如果介入协程技术那么就可以实现函数见代码切换执行,最终输入:1、3、2、4

例如:下面的代码可以实现协程

import asyncio

async def func1():
    print(1)
    await asyncio.sleep(1)  # 模拟耗时操作
    print(2)

async def func2():
    print(3)
    await asyncio.sleep(1)  # 模拟耗时操作
    print(4)

async def main():
    await asyncio.gather(func1(), func2())

asyncio.run(main())

在这里插入图片描述

协程的实现

在Python中,有多种方式可以实现协程。以下是其中几种常用的方式:

  • 使用第三方模块greenlet:greenlet是一个第三方库,它提供了协程的支持。通过使用greenlet,可以手动控制协程的切换,并实现协程之间的交替执行。
  • 使用生成器(yield):Python中的生成器也可以用于实现协程,通过yield关键字可以暂停函数的执行,并在需要时恢复执行。生成器可以作为协程函数,通过yield来实现协程的切换。
  • 使用asyncio库:Python标准库中的asyncio模块提供了对协程的支持。asyncio提供了事件循环(event loop)和协程(coroutine)的概念,可以通过async/await关键字来定义和管理协程,实现异步编程。
  • 使用async/await关键字:在Python 3.5及更高版本中,引入了async/await关键字,使得编写和管理协程更加方便。通过使用async/await关键字结合asyncio库,可以轻松地定义和管理协程,并实现异步编程。
1.greenlet
from greenlet import greenlet

def func1():
    print(1)        # 第1步:输出 1
    gr2.switch()    # 第3步:切换到 func2 函数
    print(2)        # 第6步:输出 2
    gr2.switch()    # 第7步:切换到 func2 函数,从上一次执行的位置继续向后执行

def func2():
    print(3)        # 第4步:输出 3
    gr1.switch()    # 第5步:切换到 func1 函数,从上一次执行的位置继续向后执行
    print(4)        # 第8步:输出 4

gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 第1步:去执行 func1 函数

在这里插入图片描述

提示:switch中也可以传递参数用于在切换执行时相互传递值。

2. yield

​ 生成器的yield关键字可以用于实现协程代码。通过使用yield,可以将函数切分为多个可暂停和恢复的执行点,从而实现协程的切换。

yield from可以用于等待另一个协程的执行,并将控制权转移到该协程,直到它完成或产生结果。这样可以实现协程的嵌套和协作,使得协程能够在遇到IO操作时暂停执行,并自动切换到其他协程

def func1():
    yield 1
    yield from func2()
    yield 2


def func2():
    yield 3
    yield 4


f1 = func1()
for item in f1:
    print(item)

在这里插入图片描述

3.asyncio

在Python 3.4发布后,官方引入了asyncio模块,为Python提供了官方支持的协程和异步编程框架。asyncio模块基于事件循环和协程的概念,提供了一种方便的编程模型来实现异步操作。

import asyncio

@asyncio.coroutine
def func1():
    print(1)
    yield from asyncio.sleep(2)  # 遇到IO耗时操作,自动化切换到tasks中的其他任务
    print(2)


@asyncio.coroutine
def func2():
    print(3)
    yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
    print(4)


tasks = [
    asyncio.ensure_future( func1() ),
    asyncio.ensure_future( func2() )
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

在这里插入图片描述

4 async & awit

在Python 3.5版本中,引入了asyncawait关键字,它们被用作协程的定义和异步操作的等待。相比于使用@asyncio.coroutine装饰器和yield from语法,使用asyncawait关键字能够使协程代码更加简洁和易读。

从Python 3.8版本开始,官方已经不推荐使用@asyncio.coroutine装饰器,而是建议直接使用asyncawait关键字来定义协程函数和等待异步操作的完成。这样可以提高代码的可读性和维护性,同时也更符合Python语言的发展趋势。

import asyncio

async def func1():
    print(1)
    await asyncio.sleep(2)  # 遇到IO耗时操作,自动化切换到tasks中的其他任务
    print(2)


async def func2():
    print(3)
    await asyncio.sleep(2)  # 遇到IO耗时操作,自动化切换到tasks中的其他任务
    print(4)


tasks = [
    asyncio.ensure_future(func1()),  # 将func1协程函数转换为Task对象
    asyncio.ensure_future(func2())   # 将func2协程函数转换为Task对象
]

loop = asyncio.get_event_loop()  # 创建事件循环对象
loop.run_until_complete(asyncio.wait(tasks))  # 运行协程任务直到所有任务完成

asyncio模块的核心是事件循环(event loop),它负责调度和执行协程任务。通过使用asyncawait关键字,可以定义协程函数,并在协程函数内使用await关键字来暂停协程的执行,等待异步操作的完成。

总结:

​ 在本文中,我们深入探索了Python中的协程技术,从传统的Greenlet和yield到新的async/await关键字,涵盖了多种实现协程的方法。通过这些技术,我们能够以非阻塞的方式处理并发和异步操作,提高程序的性能和响应能力。

​ 协程是一种轻量级的并发编程模型,允许我们在单个线程内实现多个独立的执行流。使用Greenlet和yield,我们可以手动切换协程的执行,实现协程间的协作。这种方式虽然灵活,但需要手动编写切换逻辑,不太直观。

​ 随着asyncio模块的引入,Python提供了更高级的异步编程功能。通过使用其中的协程和事件循环,我们可以更方便地定义和调度协程,处理IO密集型任务和并发操作。asyncio提供了丰富的工具和函数,使得异步编程变得简洁和可读性更强。

​ 最新的async/await关键字进一步简化了协程的编写和理解。通过使用async/await,我们可以直接在协程函数中等待异步操作的完成,而不再需要使用yield from语法。这使得协程代码更加易读和直观,符合Python的语法风格。

​ 总而言之,协程技术为我们提供了一种高效的并发编程方式。无论是处理IO密集型任务还是构建高性能的网络应用,协程都能发挥重要的作用。通过选择合适的工具和语法,我们可以根据具体的需求和编程风格,灵活地应用协程技术。掌握协程的概念和实现方式,将有助于提升代码的性能和可维护性,让我们在异步编程的世界中更加游刃有余。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI质差小区优化效果评估

1. 下行流量/PRB利用率和贬损用户的关系 通过分析长期贬损质差小区:下行PRB利用率/流量和小区平均每小时质差用户数成正比例关系,即小区的贬损用户会随PRB利用率/流量的增长而增长。 2. 贬损用户和流量走势 年前平均每天流量平稳的情况下,通…

世微AP5125 DC-DC降压恒流 LED车灯电源驱动IC SOT23-6

产品描述 AP5125 是一款外围电路简单的 Buck 型平均电流检测模式的 LED 恒流驱动器,适用于 8-100V 电压范围的非隔离式大功率恒流 LED 驱动领域。芯片采用固定频率 140kHz 的 PWM 工作模式, 利用平均电流检测模式,因此具有优异的负载调整 率…

酵母双杂交服务专题(三)

当开始研究某个基因时,除了识别其功能之外,还必须分析它与其他蛋白质或分子的相互作用关系。这是因为基因通常不是孤立发挥作用,而是通过与其他蛋白或分子的互动参与调节下游基因的表达。酵母双杂交技术是检测蛋白质间相互作用的一种标准方法…

车载电源测试是什么?如何用车载电源测试系统测试?

车载电源测试是为了检测电源的各项指标和性能,判断其是否符合设计要求,满足车载设备的使用。车载电源测试项目一般包含输出电压/电流测试、效率测试、过载保护测试、稳定性和可靠性测试等。用车载电源自动化测试系统进行检测不仅可以提高测试效率&#x…

MySQL之JDBC

💕"我像离家的孤儿,回到了母亲的怀抱,恢复了青春。"💕 作者:Mylvzi 文章主要内容:MySQL之JDBC 一.什么是JDBC? JDBC编程就是通过Java 代码来操纵数据库 数据库编程, 需要数据库服务器提供一些API供程序…

主成分分析例题 (多元统计分析期末复习)

例一 给定X的协差阵,对其进行主成分分析, (1)求出每个主成分的贡献率; (2)求出每个原始变量的信息提取率; 解:对于主成分分析的题,一般来说,题目给定一个协方…

centos7 nginx_keepalived 在主备服务器上安装

脚本地址 https://gitcode.net/zengliguang/nginx_keepalived.git 文件说明keepalivedkeepalived的离线安装包nginx-1.24.0nginx的离线安装包centos7_keepalived_offline_install_backup.shkeepalved安装脚本,备服务器安装 centos7_keepalived_offline_install_mas…

深入解析 Python 中 Parsel 的两种数据提取方式

更多资料获取 📚 个人网站:ipengtao.com 在网络爬虫的世界中,数据提取是至关重要的一环。Python 提供了许多强大的工具,其中之一就是 parsel 库,专门用于解析和提取 HTML 或 XML 数据。本篇博客将深入探讨 parsel 中两…

Memcached最新2023年面试题,高级面试题及附答案解析

文章目录 01、Memcached是什么,有什么作用?02、Memcached的多线程是什么?如何使用它们?03、Memcached与Redis的区别?04、如果缓存数据在导出导入之间过期了,怎么处理这些数据呢?05、如何实现集群…

机器学习入门(第五天)——决策树(每次选一边)

Decision tree 知识树 Knowledge tree 一个小故事 A story 挑苹果: 根据这些特征,如颜色是否是红色、硬度是否是硬、香味是否是香,如果全部满足绝对是好苹果,或者红色硬但是无味也是好苹果,从上图可以看出来&#…

传教士与野人过河问题

代码模块参考文章:传教士与野人过河问题(numpy、pandas)_python过河问题_醉蕤的博客-CSDN博客 问题描述 一般的传教士和野人问题(Missionaries and Cannibals):有N个传教士和C个野人来到河边准 备渡河。…

vscode集成git

1、首先电脑要安装git 打开git官网地址:Git进行下载,如下图界面: 如图片中描述:一般进入官网后会识别电脑对应系统(识别出了我的电脑是Windows系统 。如果未识别到电脑系统,可在左侧选择自己电脑对应的系统…

Maven——使用Nexus创建私服

私服不是Maven的核心概念,它仅仅是一种衍生出来的特殊的Maven仓库。通过建立自己的私服,就可以降低中央仓库负荷、节省外网带宽、加速Maven构建、自己部署构件等,从而高效地使用Maven。 有三种专门的Maven仓库管理软件可以用来帮助大家建立…

vue3使用动态component

使用场景: 多个组件通过component标签挂载在同一个组件中,通过触发时间进行动态切换。vue3与vue2用法不一样,这里有坑! 使用方法: 1.通过vue的defineAsyncComponent实现挂载组件 2.component中的is属性 父组件&am…

deque容器结构学习笔记

1.结构图 2.deque对比vector和list deque双端队列,就像是list和vector的结合 vector: 优点:1.可以随机读取 2. 空间利用率高 缺点:1. 除了尾插尾删,其他插入删除效率比较低 2. 扩容效率低 list: 优点&…

第16关 革新云计算:如何利用弹性容器与托管K8S实现极速服务POD扩缩容

------> 课程视频同步分享在今日头条和B站 天下武功,唯快不破! 大家好,我是博哥爱运维。这节课给大家讲下云平台的弹性容器实例怎么结合其托管K8S,使用混合服务架构,带来极致扩缩容快感。 下面是全球主流云平台弹…

threeJs引入模型使用3D模型(vite+React+Ts)

要在 Three.js 中使用 3D 模型,你需要加载模型文件并将其添加到场景中。Three.js 支持多种不同的模型格式,比如 OBJ、FBX、GLTF 等。 init vitelatest //创建一个vite的脚手架 选择react并配置Ts 安装three.js准备 npm install react-three/drei np…

Ubuntu Server 20.04.6下Anaconda3安装Pytorch

环境 Ubuntu 20.04.6 LTS Anaconda3-2023.09-0-Linux-x86_64.sh conda 23.7.4 Pytorch 1.11.0 安装 先创建一个工作环境,环境名叫lia: conda create -n lia python3.8环境的使用方法如下: conda activate lia # 激活环境 conda deactiv…

2021年8月18日 Go生态洞察:整合Go的网络体验

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

ps 透明印章制作

ps 透明印章制作 1、打开不透明印章2、抠出红色印章3、新建图层4、填充红色印章到新图层5、导出透明印章 1、打开不透明印章 打开ps软件,菜单栏选择 文件-打开 选择本地不透明印章 打开 2、抠出红色印章 ps菜单栏 选择 选择-色彩范围 点击色彩范围 色彩范围窗口 取…