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 asyncioasync 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 greenletdef func1():print(1)        # 第1步:输出 1gr2.switch()    # 第3步:切换到 func2 函数print(2)        # 第6步:输出 2gr2.switch()    # 第7步:切换到 func2 函数,从上一次执行的位置继续向后执行def func2():print(3)        # 第4步:输出 3gr1.switch()    # 第5步:切换到 func1 函数,从上一次执行的位置继续向后执行print(4)        # 第8步:输出 4gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 第1步:去执行 func1 函数

在这里插入图片描述

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

2. yield

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

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

def func1():yield 1yield from func2()yield 2def func2():yield 3yield 4f1 = 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 asyncioasync 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密集型任务还是构建高性能的网络应用,协程都能发挥重要的作用。通过选择合适的工具和语法,我们可以根据具体的需求和编程风格,灵活地应用协程技术。掌握协程的概念和实现方式,将有助于提升代码的性能和可维护性,让我们在异步编程的世界中更加游刃有余。

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

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

相关文章

Csharp(C#)无标题栏窗体拖动代码

C#(C Sharp)是一种现代、通用的编程语言,由微软公司在2000年推出。C#是一种对象导向的编程语言,它兼具C语言的高效性和Visual Basic语言的易学性。C#主要应用于Windows桌面应用程序、Windows服务、Web应用程序、游戏开发等领域。C…

Windows系列:windows2003-建立域

windows2003-建立域 Active Directory建立DNS建立域查看日志xp 加入域 Active Directory 活动目录是一个包括文件、打印机、应用程序、服务器、域、用户账户等对象的数据库。 常见概念:对象、属性、容器 域组件(Domain Component,DC&#x…

【开源】基于Vue.js的农村物流配送系统的设计和实现

项目编号: S 024 ,文末获取源码。 \color{red}{项目编号:S024,文末获取源码。} 项目编号:S024,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登录、注册界面2.2 系统功能2.2…

对抗产品团队中的认知偏误:给产品经理的专家建议

今天的产品经理面临着独特的挑战。他们不仅需要设计和构建创新功能,还必须了解这些功能将如何为客户带来价值并推进关键业务目标。如果不加以控制,认知偏差可能会导致您构建的内容与客户想要的内容或业务需求之间不一致。本文将详细阐述产品经理可以避免…

帮亲戚个忙,闲来有事用php写个58商铺出租转让信息抓取

最近亲戚想做点小超市生意,但是又不懂互联网,信息获取有点闭塞。知道我身在互联网大潮中,想让我帮忙看看网上有没有商铺转让的。心想,这不是小菜一碟,大显身手的时候来了,大概去58瞅了瞅,这玩意…

网狐类源码游戏配置数据库数据(一键配置网狐数据库)

网狐类源码游戏配置数据库数据(一键配置网狐数据库) 一般拿到网狐的源码或组件,需要先附加或配置数据库,以下为全部需要更改数据的地方,这里以荣耀系列版本数据库为例: 1. 数据库设置 [RYPlatformDB].…

Unity Canvas、Canvas Scaler、Graphic Raycaster、EventSystem 组件详解

文章目录 0. 参考文章1. Canvas1.1 Screen Space-Overlay —— 屏幕空间覆盖模式1.2 Screen Space-Camera —— 相机模式1.3 World Space —— 世界模式 2. Canvas Scaler:控制UI画布的放大缩放的比例2.1 Constant Pixer Size —— 恒定像素2.2 Scale With Screen S…

spring RedisTemplate RedisLockRegistry opsForXxx 基本使用总结以及介绍

一、基本介绍 RedisTemplate 为 spring 对 redis 操作的高度封装,基本已经满足所有使用场景。 若存在其他拓展使用我们可以自行封装工具类对基本操作进行组装。 RedisLockRegistry 对 redis 锁的一些封装 二、不同环境下依赖以及基本配置 2.1 spring-boot 下依赖…

反欺诈指南:东南亚数字经济反欺诈注意事项

目录 东南亚各类网络欺诈肆虐 科技助力东南亚反欺诈 东南亚做反欺诈需要注意四个方面 据谷歌、淡马锡和贝恩公司发布的一份报告显示,尽管东南亚地区的经济增长有所放缓,但2023年数字经济仍预计创造约100亿美元的收入,数字支付占该地区总交易额…

T-Rex:检测一切 | 基于视觉提示的开集检测器,检测并计数

图1. 我们引入了一个交互式对象计数模型T-Rex。给定参考图像上指定的框或点,T-Rex 可以检测目标图像上的所有与指定对象表现出相似模式的实例,然后将其相加得到计数结果。我们先通过T-Rex生成检测到框提示,再使用SAM得到mask,以获…

np.random.uniform() 采样得到的是一个高维立方体,而不是球体,为什么?

在代码中,采样是通过以下方式完成的: samples self.center np.random.uniform(-self.radius, self.radius, (num_samples, len(self.center))) 这里,np.random.uniform函数在每个维度独立地生成了一个介于-self.radius和self.radius之间的…