流畅的Python(十八)-使用asyncio包处理并发

一、核心要义

1. 对比一个简答的多线程程序和对应的asyncio版,说明多线程和异步任务之间的关系

2. 网络下载的异步版

3. 在异步编程中,与回调相比,协程显著提升性能的方式

二、代码示例

1、相关知识点

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/10 10:14
# @Author  : Maple
# @File    : 00-相关知识点.py
# @Software: PyCharm
import sysimport collectionsif __name__ == '__main__':write, flush = sys.stdout.write, sys.stdout.flushwrite('Hello world')flush()# \x08是回退符write('\x08' * 1) # Hello worlwrite('\n')write('Hello world')flush()write('\x08' * 2) # Hello wowrite('\n')write('Hello world')flush()# 如果回退长度为字符串本身长度,相当于全部被清空write('\x08' * len('Hello world'))

2、指针旋转(多线程示例)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/8 22:05
# @Author  : Maple
# @File    : 01-指针旋转(多线程示例).py
# @Software: PyCharm
import itertools
import sys
import threading
import timeclass Signal:go = Truedef spin(msg,signal):write,flush = sys.stdout.write,sys.stdout.flushfor  char in itertools.cycle('|/-\\'):status = char + ' ' + msgwrite(status)flush()write('\x08' * len(status))time.sleep(.1)if not signal.go:breakwrite(' ' * len(status) + '\x08' * len(status))def slow_function():# 假装等待IO一段时间time.sleep(3)return 42def supervisor():signal = Signal()spinner = threading.Thread(target= spin, args=('thinking',signal))# 输出从属线程对象,类似:<Thread(thread-1,initial)>print('spinner object',spinner)spinner.start()result = slow_function()signal.go = False# 等待spinner线程结束spinner.join()return resultdef main():result = supervisor()print('Answer:',result)if __name__ == '__main__':main()

3、指针旋转(asyncio示例)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/10 11:20
# @Author  : Maple
# @File    : 02-指针旋转(asyncio示例).py
# @Software: PyCharm
import asyncio
import itertools
import sys# 打算交给asyncio处理的协程要使用该装饰器(Python3.8及之后的版本中已经过时了,建议使用async代替,详见指针旋转(asyncio示例2)),并非强制,但建议这么做@asyncio.coroutine
def spin(msg):write,flush = sys.stdout.write,sys.stdout.flushfor  char in itertools.cycle('|/-\\'):status = char + ' ' + msgwrite(status)flush()write('\x08' * len(status))try:# 代替time.sleep,这样的休眠不会阻塞事件循环yield from asyncio.sleep(.1)except asyncio.CancelledError:breakwrite(' ' * len(status) + '\x08' * len(status))@asyncio.coroutine
def slow_function():# 假装等待I/0一段事件yield from asyncio.sleep(3)return 42@asyncio.coroutine
def supervisor():# 使用async函数排定spin协程运行时间,使用一个Task对象包装spin协程,并立即返回# Task对象也是一个Future对象,因为Task类是future类的一个子类spinner = asyncio.create_task(spin('thinking'))print('spinner object',spinner)# 驱动slow_function函数,结束后获取返回值(参考16章-协程中的`委派生成器`一节)"""第一级委派生成器:supervisor第二级委派生成器:slow_function"""# 同时事件循环继续运行,因为slow_function函数最后使用yield from asyncio.sleep(3)# 表达式控制权交给了主线程result = yield from slow_function()spinner.cancel()return resultdef main():# 获取事件循环的引用loop = asyncio.get_event_loop()# 驱动supervisor协程,让它运行完毕,这个协程的返回值是这次调用的返回值# 事件循环就是外部调用方(参考16章-协程中的`委派生成器`一节)result = loop.run_until_complete(supervisor())loop.close()print('Answer',result)if __name__ == '__main__':main()

4、指针旋转(asyncio示例2)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/10 11:20
# @Author  : Maple
# @File    : 02-指针旋转(asyncio示例).py
# @Software: PyCharm
import asyncio
import itertools
import sys# 由于@asyncio.coroutine装饰器在Python3.8及以后的版本中已经过时
# Python官方建议使用async代替该装饰器async def spin(msg):write,flush = sys.stdout.write,sys.stdout.flushfor  char in itertools.cycle('|/-\\'):status = char + ' ' + msgwrite(status)flush()write('\x08' * len(status))try:# 代替time.sleep,这样的休眠不会阻塞事件循环await asyncio.sleep(.1)except asyncio.CancelledError:breakwrite(' ' * len(status) + '\x08' * len(status))async def slow_function():# 假装等待I/0一段事件await asyncio.sleep(3)return 42async def supervisor():# 使用async函数排定spin协程运行时间,使用一个Task对象包装spin协程,并立即返回spinner = asyncio.create_task(spin('thinking'))print('spinner object:',spinner) # spinner object: <Task pending name='Task-2' coro=<spin() running at D:/01-study/python/fluent_python/18-使用asyncio包处理并发/03-指针旋转(asyncio示例2).py:14>>print('spinner object type:',type(spinner)) #  <class '_asyncio.Task'># 驱动slow_function函数,结束后获取返回值。同时事件循环继续运行,因为slow_function函数最后使用yield from asyncio.sleep(3)# 表达式控制权交给了主线程result = await slow_function()spinner.cancel()return resultdef main():loop = asyncio.get_event_loop()result = loop.run_until_complete(supervisor())loop.close()print('Answer',result)if __name__ == '__main__':main()

5、网络下载asyncio版本(1)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/10 12:29
# @Author  : Maple
# @File    : 04-网络下载asyncio版本(1).py
# @Software: PyCharm
import asyncio
import time
from random import randint"""
我们编程的协程链条:
1. 通过把最外层的委派生成器传给asyncio包API中的某个函数(如loop.run_until_complete驱动)即不通过调用next()或send()[对比参考16章-协程中的`委派生成器`一节]驱动协程
2. 我们编写的协程链条最终通过yield from把职责委托给asyncio包的某个协程函数或协程方法(比如本例中的asyncio.sleep(download_time))也就是说,最内层的`子生成器`是库中真正执行的I/O操作的函数,而不是我们自己编写的函数
3. 通常来说,我们编写的只是`委派生成器` 
"""CC_LIST = [1, 2, 3, 4, 5, 6]def get_randint():return randint(1, 10)async def get_img(id):print('***', id, '号图片开始下载***')download_time = get_randint()await asyncio.sleep(download_time)return download_timeasync def download_one_img(id):result  = await get_img(id)print('***{}号图片下载完成,花费时长{}s***'.format(id, result))return str(id) + '号图片内容'def download_many_img(cc_list):# 获取事件循环的引用loop = asyncio.get_event_loop()# 构建协程对象列表to_do = [download_one_img(c) for c in sorted(cc_list)]# wait方法的参数是future对象或者协程构成的可迭代对象,该方法会把各个协程包装进一个Task对象(也是Future对象,因为Task类是# Future类的子类)wait_coro = asyncio.wait(to_do)# 执行事件循环,直到wait_coro运行结束,事件循环运行的过程中,程序会在这里阻塞.# 返回的第一个元素是一系列结束的future,第二个是一系列未结束的future(此例始终为空,所以赋值给_, wait有两个关键字,如果设置了可#   能会返回未结束的future -- timeout和return_when)res,_ = loop.run_until_complete(wait_coro)loop.close()return len(res)def main(download_many_img):t0 = time.time()count = download_many_img(CC_LIST)elapsed = time.time() - t0msg = '\n{} flags downloaded in {:.2f}s'print(msg.format(count, elapsed))if __name__ == '__main__':main(download_many_img)

6、网络下载asyncio版本(2)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/10 17:50
# @Author  : Maple
# @File    : 05-网路下载asyncio版本(2).py
# @Software: PyCharm"""
使用asyncio.as_completed函数,由于
1. 该函数必须在协程中使用
2. download_many_img 不能是协程,因为main函数中需要调用download_many_img,而该参数是普通函数因此,需要新增一个 downloader_coro 协程函数,专门用于多线程(协程)下载,而 download_many_img仅用于设置事件循环
"""
import asyncio
import time
from random import randintCC_LIST = [1, 2, 3, 4, 5, 6]def get_randint():return randint(1, 10)async def get_img(id):print('***', id, '号图片开始下载***')download_time = get_randint()await asyncio.sleep(download_time)return download_timeasync def download_one_img(id):result  = await get_img(id)print('***{}号图片下载完成,花费时长{}s***'.format(id, result))return str(id) + '号图片内容'async def downloader_coro(cc_list):count = 0# 生成协程列表to_do = [download_one_img(c) for c in sorted(cc_list)]# 获取包装式Future对象to_do_iter = asyncio.as_completed(to_do)for future in to_do_iter:# 获取future(里面执行的是download_one_img函数)返回结果res = await futurecount +=1print(res)return countdef download_many_img(cc_list):# 获取事件循环的引用loop = asyncio.get_event_loop()# 实例化协程coro = downloader_coro(cc_list)res = loop.run_until_complete(coro)loop.close()return resdef main(download_many_img):t0 = time.time()count = download_many_img(CC_LIST)elapsed = time.time() - t0msg = '\n{} flags downloaded in {:.2f}s'print(msg.format(count, elapsed))if __name__ == '__main__':main(download_many_img)

7、一次性多次请求

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/10 20:14
# @Author  : Maple
# @File    : 06-每次多次请求.py
# @Software: PyCharm
import asyncio
import json
import re
from asgiref.sync import sync_to_asyncdef regex_data(data):""":param data:异步读取返回的原始数据,Sample数据如下:({<Task finished name='Task-2' coro=<get_info() done, defined at D:/01-study/python/fluent_python/18-使用asyncio包处理并发/06-每次多次请求.py:47> result='China'>}, set()):return:提取原始数据中的result部分"""regex = re.compile('result=(.*?)')result = regex.findall(str(data))return resultdef read_json(country):with open('data/name.json', 'r') as f:# returns JSON object as a  dictionarydata = json.load(f)return data[country]async def read_json_async(country_code):try:data = await sync_to_async(read_json)(country_code)except Exception as e:data = 'code不存在'return datadef read_img(path):with open(path, 'rb') as f:data = f.read()return data# f.read二级制文件 不能直接使用await
async def read_img_async(path):# 同步函数(必须有参数,否则报错,暂时未研究原因)转异步try:data = await sync_to_async(read_img)(path)except Exception as e:data = 'code不存在'return dataasync def get_info(type,code=None,path=None):# 如果传入json,就返回姓名信息if 'json' == type:data = await read_json_async(code)elif 'img' == type:# 否则返回图片信息#  直接返回的数据Sample: {<Task finished name='Task-2' coro=<read_img_sync() done, defined at D:/01-study/python/fluent_python/18-使用asyncio包处理并发/test.py:64>#   result=b'\xff\xd8\xf...8\x8c\xf6\x9f'>}data = await read_img_async(path)return dataasync def get_names(code,path):darling = await get_info('json',code=code)img_data = await get_info('img',path=path)return (darling,img_data)def download_many(code=None,path=None):loop = asyncio.get_event_loop()to_do = [get_names(code='0001', path ='data/profile_photo.jpg'), get_names(code='0002', path ='data/profile_photo.jpg')]wait_coro = asyncio.wait(to_do)# ({<Task finished name='Task-2' coro=<get_info() done, defined at D:/01-study/python/fluent_python/18-使用asyncio包处理并发/06-每次多次请求.py:47> result='China'>}, set())datas = loop.run_until_complete(wait_coro)print(datas)for i in range(len(datas)):# 解析数据if datas[i]:data = regex_data(datas[i])[0]print(data)loop.close()def main(download_many):data = download_many()if __name__ == '__main__':main(download_many)

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

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

相关文章

算法50:动态规划专练(力扣514题:自由之路-----4种写法)

题目: 力扣514 &#xff1a; 自由之路 . - 力扣&#xff08;LeetCode&#xff09; 题目的详细描述&#xff0c;直接打开力扣看就是了&#xff0c;下面说一下我对题目的理解: 事例1&#xff1a; 输入: ring "godding", key "gd" 输出: 4. 1. ring的第…

RStudio更换R语言版本

今天下载R语言用于读取.xlsx文件的readxl包时&#xff0c;RStudio提示该包是使用R-4.3.3版本构建&#xff0c;而我现在使用的是R-4.3.2版本&#xff0c;所以需要升级一下R语言版本&#xff0c;这里先下载最新版本的R语言&#xff0c; 下载地址&#xff1a;The Comprehensive R…

Jenkins自动构建 CI/CD流水线学习笔记(从入门到入土,理论+示例)

文章目录 1、什么是Jenkins的流水线?2、流水线语法2.1、声明式流水线2.2、脚本化流水线 3、流水线示例3.1、使用声明式流水线的语法编写的 Jenkinsfile 文件3.2、Pipeline 各种语言示例3.2.1 Java&#xff1a;3.2.2 Node.js / JavaScript3.2.3 Python 4、一套完整的Devops Jen…

【ICCV21】Swin Transformer: Hierarchical Vision Transformer using Shifted Windows

文章目录 0. Abstract1. Introduction2. Related Work3. Method3.1 Overall Architecture3.2 Shifted Window based Self-Attention3.3 Architecture Variants 4. Experiments4.1 Image Classification on ImageNet-1K4.2 Object Detection on COCO4.3 Semantic Segmentation o…

基于JavaWeb开发的springboot网咖管理系统[附源码]

基于JavaWeb开发的springboot网咖管理系统[附源码] &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 &a…

【办公类-40-02】20240311 python模仿PPT相册功能批量插入照片,更改背景颜色 (家长会系列二)

作品展示——用Python插入PPT相册 背景需求&#xff1a; 马上就要家长会&#xff0c;我负责做会议前的照片滚动PPT&#xff0c;通常都是使用PPT的相册功能批量导入照片&#xff0c; 生成给一个新的PPT文件 更改背景颜色 设置4秒间隔&#xff0c;应用到全部 保存&#xff0c;改…

Hadoop伪分布式配置--没有DataNode或NameNode

一、原因分析 重复格式化NameNode 二、解决方法 1、输入格式化NameNode命令&#xff0c;找到data和name存放位置 ./bin/hdfs namenode -format 2、删除data或name&#xff08;没有哪个删哪个&#xff09; sudo rm -rf data 3、重新格式化NameNode 4、重新启动即可。

sheng的学习笔记- AI-类别不平衡问题

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 什么是类别不平衡问题 类别不平衡&#xff08;class-imbalance&#xff09;&#xff0c;也叫数据倾斜&#xff0c;数据不平衡&#xff0c;就是指分类任务中不同类别的训练样例数目差别很大的情况。 例如有998个反例&#xf…

vue3全局引入element-plus后怎么使用Message进行消息提示

全局引入 main.ts import element-plus/dist/index.css 在需要使用提示的组件中引入 import { ElMessage } from element-plus 使用举例

Verilog刷题笔记37

题目&#xff1a;3位二进制加法器 Now that you know how to build a full adder, make 3 instances of it to create a 3-bit binary ripple-carry adder. The adder adds two 3-bit numbers and a carry-in to produce a 3-bit sum and carry out. To encourage you to actua…

@Conditional注解详解

目录 一、Conditional注解作用 二、Conditional源码解析 2.1 Conditional源码 2.2 Condition源码 三、Conditional案例 3.1 Conditional作用在类上案例 3.1.1 配置文件 3.1.2 Condition实现类 3.1.3 Bean内容类 3.1.4 Config类 3.1.5 Controller类 3.1.6 测试结果 3…

Visual grounding-视觉定位任务介绍

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

Spring Cloud Alibaba微服务从入门到进阶(一)

Springboot三板斧 1、加依赖 2、写注解 3、写配置 Spring Boot Actuator Spring Boot Actuator 是 Spring Boot 提供的一系列用于监控和管理应用程序的工具和服务。 SpringBoot导航端点 其中localhost:8080/actuator/health是健康检查端点&#xff0c;加上以下配置&#xf…

基于element-plus的Dialog选择控件

翻看之前工程师写的vue2的代码&#xff0c;很多都是复制、粘贴&#xff0c;也真是搞不懂&#xff0c;明明可以写一个控件&#xff0c;不就可以重复使用。很多前端总喜欢element搞一下&#xff0c;ant-design也搞一下&#xff0c;有啥意义&#xff0c;控件也不是自己写的&#x…

Python递归函数你用对了吗?

1.递归函数 递归函数&#xff1a;函数自己调用自己 2.需求 使用函数的方式&#xff0c;计算数字n的阶乘 # 5&#xff01; """ 5! 1 * 2 * 3 * 4 * 5 4! 1 * 2 * 3 * 4 3! 1 * 2 * 3 2! 1 * 2 1! 1综上可以总结出&#xff1a;n! n * (n - 1) "&qu…

什么是防静电晶圆隔离膜?一分钟让你了解抗静电晶圆隔离纸

防静电晶圆隔离膜&#xff0c;也被称为防静电蓄积纸、硅片纸、半导体晶圆盒内缓冲垫片等多种名称&#xff0c;是半导体制造和运输过程中的一种重要辅助材料。 该隔离膜具备多种特性&#xff0c;如防静电、无尘、不掉屑、强韧耐用等&#xff0c;这些特性使其在半导体制造和运输中…

网络安全之从原理看懂XSS

01、XSS的原理和分类 跨站脚本攻击XSS(Cross Site Scripting)&#xff0c;为了不和层叠样式表(Cascading Style Sheets&#xff0c;CSS)的缩写混淆 故将跨站脚本攻击缩写为XSS&#xff0c;恶意攻击者往Web页面里插入恶意Script代码&#xff0c;当用户浏览该页面时&#xff0c…

Word转PDF保持图片原有清晰度

目录 1、需要的软件 2、配置Acrobat PDFMaker 3、配置Acrobat Distiller 4、更改Acrobat PDFMaker中的首选项 5、将word转换成pdf 1、需要的软件 利用Adobe Acrobat DC工具。 打开word&#xff0c;选择Acrobat的插件&#xff0c;选择首选项。 如果没有出现Acrobat插件也…

java并发编程知识点汇总

文章目录 1. Java8新特性1.1 Lambda表达式1.2 函数式接口1.3 Stream流式计算&#xff0c;应用了上述函数式接口能力1.4 接口增强 2. 常用原子类3. 多线程与高并发-juc3.1 谈一谈对volatile的理解3.2 谈一谈对JMM的理解3.3 谈一谈对CAS及底层原理的理解3.4 谈一谈对ABA问题及原子…

【恒源智享云】conda虚拟环境的操作指令

conda虚拟环境的操作指令 由于虚拟环境经常会用到&#xff0c;但是我总忘记&#xff0c;所以写个博客&#xff0c;留作自用。 在恒源智享云上&#xff0c;可以直接在终端界面输入指令&#xff0c;例如&#xff1a; 查看已经存在的虚拟环境列表 conda env list查看当前虚拟…