python 协程

1. 协程

协程,又称微线程,纤程。英文名Coroutine。
https://www.cnblogs.com/coder-qi/p/10163416.html

协程不是计算机提供的,是人为创造的上下文切换技术,也可以被称为微线程。简而言之 其实就是在一个线程中实现代码块相互切换执行。
可以采用以下几种基于协程的方式:

  • greenlet。
  • yield 关键字
  • asyncio 装饰器(py3.4之后引入)
  • async、await关键字(py3.5之后引入)【推荐】

1.1. greenlet 实现协程

# greenlet是第三方模块需先引入
pip3 install greenlet
# -*- coding: utf-8 -*-
from greenlet import greenletdef func1():print(1)        # 第二步:输出1gr2.switch()    # 第三步:切换到 func2 函数print(2)        # 第六步:输出2gr2.switch()    # 第七步:切换到func2 函数(如果不切换的话句柄会继续往下执行,也就不会进入func2 输出4)def func2():print(3)        # 第四步:输出3gr1.switch()    # 第五步:切换到func1 函数print(4)        # 第八步:输出4,func2函数 执行完毕句柄继续往下执行def func3():print(5)        # 第十步:输出5gr1 = greenlet(func1)  # 此处只是生成 greenlet 包装的 func1 对象,代码并不会实际运行
gr2 = greenlet(func2)  # 此处生成 greenlet 包装的 func2 对象gr1.switch()  			# 第一步:此处是正式执行 func1() 对象
func3() 	 			# 第九步:实例化 func3

运行结果:

1
3
2
4
5

1.2. yield 关键字

不推荐,实际应用场景比较少。
实例1:

def func1():yield 1yield from func2()  # 这里其实相当于for item in func2(): yield itemyield 2def func2():yield 3yield 4for item in func1():print(item)

运行结果

1
3
4
2

实例2:
参考:https://www.cnblogs.com/coder-qi/p/10163416.html

import timedef test1():index=0while True:#print("--test1--")yield f"test1 {index}"time.sleep(0.5)index += 1def test2():index=0while True:#print("--test2--")yield f"test2 {index}"time.sleep(0.5)index += 1if __name__ == "__main__":t1 = test1()t2 = test2()while True:print(next(t1))print(next(t2))

运行结果:

test1 0
test2 0
test1 1
test2 1
test1 2
test2 2
test1 3
test2 3

1.3. asyncio 模块

参考:https://www.cnblogs.com/micheryu/p/15779377.html
在 python3.4 及之后的版本才可使用,这个框架使用事件循环来编排回调和异步任务。事件循环位于事件循环策略的上下文中。
下图是协程,事件循环和策略之间的相互作用
asyncio
注意:asyncio 牛逼在于遇到 IO 阻塞自动切换!

1.3.1. 使用 @asyncio.coroutine 装饰器

下面我们使用 @asyncio.coroutine 装饰器(py3.10+会移除) 定义了两个协程函数。(基于生成器的协程)

import asyncio@asyncio.coroutine
def func1():print(1)# 此处用asyncio.sleep(2)来模拟IO耗时(asyncio.sleep也是一个协程对象,不能用time.sleep()),asyncio定义的协程函数遇到IO操作时
会自动切换到事件循环中的其他任务yield from asyncio.sleep(2)print(2)# 暂未使用
@asyncio.coroutine
def func2():print(3)yield from asyncio.sleep(2)print(4)print(asyncio.iscoroutine(func1()))loop = asyncio.get_event_loop()
loop.run_until_complete(func1())

运行结果:

/*/demo.py:4: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" insteaddef func1():
/*/demo.py:11: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" insteaddef func2():
True
/*/demo.py:18: DeprecationWarning: There is no current event looploop = asyncio.get_event_loop()
1
2

PS:如果 py 版本高于3.8依然可以使用 asyncio.coroutine 装饰器但是会有告警建议你使用 async & await 关键字来定义协程函数,不会影响使用!
协程函数并不能像普通函数一样直接实例化运行,调用协程函数协程并不会开始运行,只是返回一个协程对象。可以通过 asyncio.iscoroutine 来验证是否是协程对象。

print(asyncio.iscoroutine(func1()))  # True

协程对象必须在事件循环中运行,我们可以通过 asyncio.get_event_loop 方法来获取当前正在运行的循环实例。如 loop 对象,然后把协程对象交给 loop.run_until_complete,协程对象随后会在 loop 里得到运行。
run_until_complete 是一个阻塞(blocking)调用,直到协程运行结束,它才返回;所以他必须接受的是一个可等待对象(协程,任务 和future对象)。

1.3.2. 可等待对象

协程对象:协程函数实例化后就是协程对象
future 对象:asyncio.futures.Future 对象用来链接 底层回调式代码和高层异步/等待式代码,可以简单理解为 future 对象是可以使程序 hang在某个地方等待有结果了之后再继续执行。

1.3.2.1. 创建 future 对象:loop.create_future()
import asyncioasync def main():# 获取当前事件循环loop = asyncio.get_running_loop()# 单单只是创建一个future对象fut = loop.create_future()# future对象因为什么都没做也就没返回值,所以 await 会一直等待下去程序就会 hang 住await futasyncio.run(main())
# 这句永远都不会执行
print(1)
1.3.2.2. future 对象.set_result() 方法
async def func(fut):fut.set_result("finish")async def main():# 获取当前事件循环loop = asyncio.get_running_loop()# 单单只是创建一个future对象fut = loop.create_future()# 创建一个task对象,绑定了func函数并且把我们创建的fut对象传递给了协程对象func;func协程函数内部又对fut对象设置了resultawait loop.create_task(func(fut))# 由于设置了fut对象的结果,下面的await就能拿到结果 所以程序就可以继续往下执行了print(await fut)asyncio.run(main())
print(1)

运行结果:

finish
1

任务:

1.4. async & await 关键字【推荐🌟】

参考:https://www.cnblogs.com/micheryu/p/15779377.html
py3.5 及之后版本
本质上和3.4的 asyncio 一致,但更强大。
3.5之后 yield from 不可以在 async 定义的函数内使用,需使用 await。
实例1:
参考:https://blog.csdn.net/u011089760/article/details/90542894

import asyncio
import timeasync def job(t):                   # async 形式的功能print('Start job ', t)# 等待 "t" 秒, 期间切换其他任务。# 此处用 asyncio.sleep(t) 来模拟 IO 耗时(asyncio.sleep 也是一个协程对象,不能用 time.sleep())# asyncio 定义的协程函数遇到 IO 操作时会自动切换到事件循环中的其他任务await asyncio.sleep(t)         print('Job ', t, ' takes ', t, ' s')async def main(loop):                       # async 形式的功能tasks = [loop.create_task(job(t)) for t in range(1, 4)]                                       # 创建任务, 但是不执行await asyncio.wait(tasks)               # 执行并等待所有任务完成t1 = time.time()
loop = asyncio.get_event_loop()             # 建立 loop
loop.run_until_complete(main(loop))         # 执行 loop,并且等待所有任务结束
loop.close()                                # 关闭 loop
print("Async total time : ", time.time() - t1)

运行结果:

Start job  1
Start job  2
Start job  3
Job  1  takes  1  s
Job  2  takes  2  s
Job  3  takes  3  s
Async total time :  3.0052335262298584

实例2:

import asyncioasync def func1():print(1)await asyncio.sleep(2)  # 遇到IO自动切换任务;等待2秒, 期间切换其他任务print(2)async def func2():print(3)await asyncio.sleep(2)  # 此处又遇到IO阻塞后,又会自动切换到tasks中其他的任务print(4)tasks = [asyncio.ensure_future(func1()),  # 把协程对象包转成一个 future 对象asyncio.ensure_future(func2())
]loop = asyncio.get_event_loop()
# 执行单个协程函数
loop.run_until_complete(func1())  # 由于func1中使用了await关键字所以此处等同于asyncio.wait
""" 输出结果为:
1
等待2s
2
"""
# 执行多个协程函数
loop.run_until_complete(asyncio.wait(tasks))
""" 输出结果为:
1
3
等待2s
2
4
"""

注:python3.7 之后可以不需要自己获取 loop 对象,可以直接调用 asyncio.run() 方法内部已经帮我们获取了 loop 对象和调用loop.run_until_complete(),但是不支持同时运行多个协程对象。

asyncio.run(func1()) 

async & await 关键字简化代码的同时并且兼容基于生成器的老式协程。

@asyncio.coroutine
def old_style_coroutine():yield from asyncio.sleep(1)async def main():await old_style_coroutine()

一个协程函数中可以使用多次 await 关键字。

import asyncioasync def func():print("start")await asyncio.sleep(5)print("end")return "finish"async def main():print("执行main方法")resp1 = await func()print(f"第一次返回值:{resp1}")resp2 = await func()print(f"第二次返回值:{resp2}")asyncio.run(main())

运行结果:

执行main方法
start
end
第一次返回值:finish
start
end
第二次返回值:finish

同样我们也可以在一个协程函数中获取多个其他协程对象的返回值:

import asyncioasync def func():print(1)await asyncio.sleep(2)print(2)return f"func was done"async def main():print("main开始")# 创建协程,将协程封装到Task对象中并添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。# 在调用task_list = [asyncio.create_task(func(), name="n1"),asyncio.create_task(func(), name="n2")]print("main结束")# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。# 此处的await是等待所有协程执行完毕,并返回两个集合 done、pending。done存放已完成的task对象,pending存放未完成的task对象# 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中。done, pending = await asyncio.wait(task_list, timeout=None)print("done", done)print("pending", pending)for coroi in done:print(coroi.result())#print(list(done)[0].result())asyncio.run(main())

运行结果:

main开始
main结束
1
1
2
2
done {<Task finished name='n1' coro=<func() done, defined at /*/demo.py:3> result='func was done'>, <Task finished name='n2' coro=<func() done, defined at /*/demo.py:3> result='func was done'>}
pending set()
func was done
func was done

1.5. 协程任务调用普通函数

普通函数调用协程函数:

async def func3():print('i`m func3')await asyncio.sleep(2)print('func3 finished')def func4():print('i`m func4')asyncio.run(func3())print('func4 finished')func4()"""输出结果:
i`m func4
i`m func3
等待2s
func3 finished
func4 finished
"""

协程函数调用普通函数

def func5():print('i`m func5')time.sleep(2)print('func5 finished')async def func6():print('i`m func6')func5()print('func6 finished')asyncio.run(func6())
print('all finish')
"""
i`m func6
i`m func5
等待2s
func5 finished
func6 finished
all finish
"""

1.6 实例

  1. async 定义的函数是协程函数,调用协程函数返回协程对象
  2. await 可以处理可等待对象,可等待对象有协程对象(corotine)、任务对象(task,用于顶层操作,必须作用于协程对象)和未来对象(future,底层操作 task 的父类)
  3. 协程的核心是事件循环,目的是合理的调度可等待对象的执行逻辑从而优化io等待时间
  4. 事件循环的最小调度单元是任务,通过主动的将协程对象封装成的协程任务并注册到事件循环并通过内部的调度算法调度执行
  5. 运行协程函数需要使用特定的接口调用如 asyncio.run(main()),它会启动一个事件循环并将 main() 作为任务注册到事件循环中调度执行

参考:(没有分析完)
https://blog.csdn.net/weixin_44689630/category_8872679.html
https://blog.csdn.net/weixin_44689630/article/details/122509483

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

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

相关文章

Lesson 08 string类 (中)

C&#xff1a;渴望力量吗&#xff0c;少年&#xff1f; 文章目录 二、string类的介绍与使用2. 使用&#xff08;5&#xff09;string类对象的修改操作 三、拷贝1. 引入2. 浅拷贝3. 深拷贝 总结 二、string类的介绍与使用 2. 使用 &#xff08;5&#xff09;string类对象的修改…

Scrum敏捷开发流程及支撑工具

Scrum是一种敏捷开发框架&#xff0c;用于管理复杂的项目。以下这些步骤构成了Scrum敏捷开发流程的核心。通过不断迭代、灵活应对变化和持续反馈&#xff0c;Scrum框架帮助团队快速交付高质量的产品。 以下是Scrum敏捷开发流程的基本步骤&#xff1a; 产品Backlog创建&#xf…

微服务--06--Sentinel 限流、熔断

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.微服务保护雪崩问题服务保护方案1.1.请求限流1.2.线程隔离1.3.服务熔断 2.Sentinel2.1.介绍和安装官方网站&#xff1a;[https://sentinelguard.io/zh-cn/](https…

打造高效项目团队,离不开有效的反馈机制

为了确保项目高效交付&#xff0c;项目经理需要在管理过程中及时发现问题并解决&#xff0c;所以80%的时间都在进行沟通以及各种项目汇报。但项目经理往往会陷入低频沟通、无意义汇报的困局&#xff0c;进而导致四处救火、项目各种延误、团队的工作效率低下。例如&#xff1a; …

Leetcode2336 无限集中的最小数字

题目&#xff1a; 现有一个包含所有正整数的集合 [1, 2, 3, 4, 5, ...] 。 实现 SmallestInfiniteSet 类&#xff1a; SmallestInfiniteSet() 初始化 SmallestInfiniteSet 对象以包含 所有 正整数。int popSmallest() 移除 并返回该无限集中的最小整数。void addBack(int nu…

VERAS:AI驱动的Revit可视化渲染插件

Veras 是一款基于生成式AI 的可视化工具&#xff0c;可以使用自然语言生成3D渲染效果&#xff0c;兼容Revit、Rhino 和 SketchUp。Veras for Revit工具使用 Revit 模型内部的 3D 视图。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编…

如何把ipa文件(iOS安装包)安装到iPhone手机上? 附方法汇总

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 技术细节 目录 Appuploader 常见错误及解决方法 苹果APP安装包ipa如何安装在手机上&#xff1f;很多人不知道怎么把ipa文件安装到手机上&#xff0c;这里就整理了苹果APP安装到iOS设备上的方式&#xff0c;仅供参考 苹…

说说你对slot的理解?slot使用场景有哪些?

面试官&#xff1a;说说你对slot的理解&#xff1f;slot使用场景有哪些&#xff1f; 一、slot是什么 在HTML中 slot 元素 &#xff0c;作为 Web Components 技术套件的一部分&#xff0c;是Web组件内的一个占位符 该占位符可以在后期使用自己的标记语言填充 举个栗子 <t…

安科瑞智能照明系统在福建二建大厦项目上的应用

【摘要】&#xff1a;智能化已经成为当今建筑发展的主流技术、涵盖从空调系统、消防系统到安全防范系统以及完善的计算机网络和通信系统。但是长期以来、智能照明在国内一直被忽视、大多数建筑物仍然沿用传统的照明控制方式、部分智能大厦采用楼宇自控&#xff08;BA&#xff0…

vue2全局混入正确使用场景和错误场景示例

全局混入在 Vue.js 中的使用场景需要谨慎考虑&#xff0c;因为它会影响所有组件。以下是一些正确和错误的使用场景的例子&#xff1a; 正确的使用场景&#xff1a; 全局工具方法&#xff1a; // 正确的使用场景 Vue.mixin({methods: {$formatDate: function (date) {// 格式化…

算法面试题--树与对象数组的转化

1. Array -> Tree var arr [{ id: 12, parentId: 1, name: "朝阳区" },{ id: 241, parentId: 24, name: "田林街道" },{ id: 31, parentId: 3, name: "广州市" },{ id: 13, parentId: 1, name: "昌平区" },{ id: 2421, parentId:…

曲面拼接oled屏幕为何受到企业展览青睐

曲面拼接OLED屏幕受到企业展览青睐的原因主要有以下几点&#xff1a; 创新的技术&#xff1a;曲面拼接OLED屏幕采用先进的OLED技术&#xff0c;具有自发光原理&#xff0c;可以实现真正的黑色和高对比度&#xff0c;呈现出生动的图像。其每个像素都能独立发光&#xff0c;没有背…

Windows系统下使用PHPCS+PHPMD+GIT钩子

前言 使用PHPCSGIT钩子保障团队开发中代码风格一致性实践 使用PHPMD提高代码质量与可读性 0.介绍 PHP_CodeSniffer php代码嗅探器 包含phpcs(php code standard 代码标准) phpcbf(php code beautify fix 代码美化修复) 是一个代码风格检测工具,着重代码规范 它包含两类脚本…

有时出厂重置BIOS是解决电脑问题和保持其最佳性能的好办法,主要有两种方法

​BIOS是计算机开机时启动的第一个程序&#xff0c;它有助于执行一些基本的计算机操作&#xff0c;并管理计算机和安装在计算机上的操作系统之间的命令。与任何其他程序一样&#xff0c;如果在启动计算机时遇到问题或在计算机中添加了新硬件&#xff0c;则可能需要将BIOS重置为…

「幻醒蓝」可视化主题套件|融合天空的清澈与海洋的深邃

现如今&#xff0c;数据可视化已成为信息传递的重要手段之一。在这样一个信息爆炸的时代&#xff0c;向人们传达正确的信息显得尤为重要。为此&#xff0c;可视化主题套件应运而生&#xff0c;提供了一种多样化的、可视化的方式来展示数据。不同的主题套件能够适应不同的信息传…

免费的电脑AI写作工具-5款好用的智能AI写作软件

随着人工智能&#xff08;AI&#xff09;技术的不断进步&#xff0c;电脑AI写作已经成为现代写作领域的一项不可或缺的工具。通过深度学习和自然语言处理的融合&#xff0c;AI写作软件得以模拟人类的创造性和表达能力&#xff0c;为我们提供了快速、高效地生成优质文字内容的可…

15.spring源码解析-invokeBeanFactoryPostProcessors

BeanFactoryPostProcessor接口允许我们在bean正是初始化之前改变其值。此接口只有一个方法: void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);有两种方式可以向Spring添加此对象: 通过代码的方式: context.addBeanFactoryPostProcessor 通过xml…

springboot+netty化身Udp服务端,go化身客户端模拟设备实现指令联动

&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 springbootnetty化身Udp服务端&#xff0c;go化身客户端模拟设备实现指令联动 &#x1f517;涉及链接前言异步通信的优势异步通信的优势&#xff1a;异步通信的应用场景&…

电子学会 2023年9月 青少年软件编程Python编程等级考试二级真题解析(选择题+判断题+编程题)

青少年编程Python编程等级考试二级真题解析(选择题+判断题+编程题) 2023年9月 一、选择题(共25题,共50分) 以下代码运行结果是?( ) A. 宸宸 B. 杭杭 C. 玉玉 D. 州州 答案选:A 考点分析:考察python 列表操作 jxw=yyh[2][0],jxw的值是“拱宸桥”,jxw[1]的值是“宸”…

Java实现飞翔的鸟小游戏

Java实现飞翔的鸟小游戏 1.准备工作 创建一个新的Java项目命名为“飞翔的鸟”&#xff0c;并在src中创建一个包命名为“com.qiku.bird"&#xff0c;在这个包内分别创建4个类命名为**“Bird”、“BirdGame”、“Column”、“Ground”&#xff0c;并向需要的图片**素材导入…