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,一经查实,立即删除!

相关文章

面向对象设计模式入门知识

设计模式 面向对象设计原则 依赖倒置原则&#xff08;DIP&#xff09; 高层模板(稳定)不应该依赖于低层模板(变化)&#xff0c; 二者都应该依赖抽象(稳定)抽象(稳定)不应该依赖于实现细节(变化)&#xff0c;实现细节应该依赖抽象(稳定) 开放封闭原则(OCP) 对扩展开放&…

Lesson 08 string类 (中)

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

2023年下半年计算机等级考试—信息安全三级部分真题

1.前言 刚参加完2023年下半年计算机等级考试—信息安全三级。笔者凭借记忆将考到的题进行如下汇总,并整理正确答案。仅供各位参考! 2.题型及分值 上机考试,考试时长120分钟,满分100分。 选择题 60分 50道题,每道题1.2分 填空题 20分 20道题 每道题1分 综合应用题 2…

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

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

基于协同过滤算法的美食推荐系统研究与实现

点我完整下载&#xff1a;基于协同过滤算法的美食推荐系统研究与实现 基于协同过滤算法的美食推荐系统研究与实现 "Research and Implementation of a Food Recommendation System based on Collaborative Filtering Algorithm" 目录 目录 2 摘要 3 关键词 3 第一章 …

Windows系统Powershell自带的Test-NetConnection命令测试网络情况

Test-Connection it-000571,192.168.20.205 //测试ip连通性&#xff0c;类似ping&#xff0c;用,号可以同时测试多个IP Test-NetConnection -Computername it-000571 -traceRoute //追踪域名it-000571的路由 Test-NetConnection 192.168.75.216 -port 3389 //…

微服务--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在线编…

ES6模板字符串的基本使用

ES6新增了模板字符串&#xff0c;让我们拼接字符串时更方便 注意:切记使用反引号作为字符串的定界符分隔的字面量 1.拼接 在我们模板字符串出现之前&#xff0c;我们想要拼接字符串是比较麻烦的 const name "杰克";const age 18;// 以前的拼接字符串console.log(…

如何把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…

pm2部署vue项目,Vue项目的部署在服务器

这是一篇介绍pm2简单实用的文章&#xff0c; 以启动vue项目为例&#xff0c;动态部署Vue项目&#xff0c;部署后便可直接访问服务器的Vue项目 1.安装pm2 npm install pm2 -g2.启动Vue项目 进入vue项目的目录&#xff0c;创建一个js文件&#xff0c; # 在vue项目下创建一个j…

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

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

如何使用 RestTemplate 进行 Spring Boot 微服务通信示例?

在 Spring Boot 微服务架构中&#xff0c;RestTemplate 是一个强大的工具&#xff0c;用于简化微服务之间的通信。下面是一个简单的示例&#xff0c;演示如何使用 RestTemplate 进行微服务之间的 HTTP 通信。 首先&#xff0c;确保你的 Spring Boot 项目中已经添加了 spring-b…

项目问题总结

加油&#xff01; 文章目录 1. 二次封装 axios 做了什么2. 路由的生命周期3、 vue2 和 vue3的区别4、vuex 1. 二次封装 axios 做了什么 请求拦截 成功&#xff1a; 头部添加token失败&#xff1a; 返回错误信息 响应拦截 如果没有 token &#xff0c;就提示转为登录页 路由守…

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

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;没有背…