python之异步编程
一、异步编程概述
异步编程是一种并发编程的模式,其关注点是通过调度不同任务之间的执行和等待时间,通过减少处理器的闲置时间来达到减少整个程序的执行时间;异步编程跟同步编程模型最大的不同就是其任务的切换,当遇到一个需要等待长时间执行的任务的时候,我们可以切换到其他的任务执行;
与多线程和多进程编程模型相比,异步编程只是在同一个线程之内的的任务调度,无法充分利用多核CPU的优势,所以特别适合IO阻塞性任务;
python版本 3.9.5
二、python的异步框架模型
python提供了asyncio模块来支持异步编程,其中涉及到coroutines、event loops、futures三个重要概念;
event loops主要负责跟踪和调度所有异步任务,编排具体的某个时间点执行的任务;
coroutines是对具体执行任务的封装,是一个可以在执行中暂停并切换到event loops执行流程的特殊类型的函数;其一般还需要创建task才能被event loops调度;
futures负责承载coroutines的执行结果,其随着任务在event loops中的初始化而创建,并随着任务的执行来记录任务的执行状态;
异步编程框架的整个执行过程涉及三者的紧密协作;
首先event loops启动之后,会从任务队列获取第一个要执行的coroutine,并随之创建对应task和future;
然后随着task的执行,当遇到coroutine内部需要切换任务的地方,task的执行就会暂停并释放执行线程给event loop,event loop接着会获取下一个待执行的coroutine,并进行相关的初始化之后,执行这个task;
随着event loop执行完队列中的最后一个coroutine才会切换到第一个coroutine;
随着task的执行结束,event loops会将task清除出队列,对应的执行结果会同步到future中,这个过程会持续到所有的task执行结束;

三、顺序执行多个可重叠的任务
每个任务执行中间会暂停给定的时间,循序执行的时间就是每个任务执行的时间加和;
import time
def count_down(name, delay):
indents = (ord(name) - ord('A')) * '\t'
n = 3
while n:
time.sleep(delay)
duration = time.perf_counter() - start
print('-' * 40)
print(f'{duration:.4f} \t{indents}{name} = {n}')
n -= 1
start = time.perf_counter()
count_down('A', 1)
count_down('B', 0.8)
count_down('C', 0.5)
print('-' * 40)
print('Done')
# ----------------------------------------
# 1.0010 A = 3
# ----------------------------------------
# 2.0019 A = 2
# ----------------------------------------
# 3.0030 A = 1
# ----------------------------------------
# 3.8040 B = 3
# ----------------------------------------
# 4.6050 B = 2
# ----------------------------------------
# 5.4059 B = 1
# ----------------------------------------
# 5.9065 C = 3
# ----------------------------------------
# 6.4072 C = 2
# ----------------------------------------
# 6.9078 C = 1
# ----------------------------------------
# Done
四、异步化同步代码
python在语法上提供了async、await两个关键字来简化将同步代码修改为异步;
async使用在函数的def关键字前边,标记这是一个coroutine函数;
await用在conroutine里边,用于标记需要暂停释放执行流程给event loops;
await 后边的表达式需要返回waitable的对象,例如conroutine、task、future等;
asyncio模块主要提供了操作event loop的方式;
我们可以通过async将count_down标记为coroutine,然后使用await和asyncio.sleep来实现异步的暂停,从而将控制权交给event loop;
async def count_down(name, delay, start):
indents = (ord(name) - ord('A')) * '\t'
n = 3
while n:
await asyncio.sleep(delay)
duration = time.perf_counter() - start
print('-' * 40)
print(f'{duration:.4f} \t{indents}{name} = {n}')
n -= 1
我们定义一个异步的main方法,主要完成task的创建和等待任务执行结束;
async def main():
start = time.perf_counter()
tasks = [asyncio.create_task(count_down(name,delay,start)) for name, delay in [('A', 1),('B', 0.8),('C', 0.5)]]
await asyncio.wait(tasks)
print('-' * 40)
print('Done')
执行我们可以看到时间已经变为了执行时间最长的任务的时间了;
asyncio.run(main())
# ----------------------------------------
# 0.5010 C = 3
# ----------------------------------------
# 0.8016 B = 3
# ----------------------------------------
# 1.0011 A = 3
# ----------------------------------------
# 1.0013 C = 2
# ----------------------------------------
# 1.5021 C = 1
# ----------------------------------------
# 1.6026 B = 2
# ----------------------------------------
# 2.0025 A = 2
# ----------------------------------------
# 2.4042 B = 1
# ----------------------------------------
# 3.0038 A = 1
# ----------------------------------------
# Done
五、使用多线程克服具体任务的异步限制
异步编程要求具体的任务必须是coroutine,也就是要求方法是异步的,否则只有任务执行完了,才能将控制权释放给event loop;
python中的concurent.futures提供了ThreadPoolExecutor和ProcessPoolExecutor,可以直接在异步编程中使用,从而可以在单独的线程或者进程至今任务;
import time
import asyncio
from concurrent.futures import ThreadPoolExecutor
def count_down(name, delay, start):
indents = (ord(name) - ord('A')) * '\t'
n = 3
while n:
time.sleep(delay)
duration = time.perf_counter() - start
print('-'*40)
print(f'{duration:.4f} \t{indents}{name} = {n}')
n -=1
async def main():
start = time.perf_counter()
loop = asyncio.get_running_loop()
executor = ThreadPoolExecutor(max_workers=3)
fs = [
loop.run_in_executor(executor, count_down, *args) for args in [('A', 1, start), ('B', 0.8, start), ('C', 0.5, start)]
]
await asyncio.wait(fs)
print('-'*40)
print('Done.')
asyncio.run(main())
# ----------------------------------------
# 0.5087 C = 3
# ----------------------------------------
# 0.8196 B = 3
# ----------------------------------------
# 1.0073 A = 3
# ----------------------------------------
# 1.0234 C = 2
# ----------------------------------------
# 1.5350 C = 1
# ----------------------------------------
# 1.6303 B = 2
# ----------------------------------------
# 2.0193 A = 2
# ----------------------------------------
# 2.4406 B = 1
# ----------------------------------------
# 3.0210 A = 1
# ----------------------------------------
# Done.
python之异步编程的更多相关文章
- Python的异步编程[0] -> 协程[0] -> 协程和 async / await
协程 / Coroutine 目录 生产者消费者模型 从生成器到异步协程– async/await 协程是在一个线程执行过程中可以在一个子程序的预定或者随机位置中断,然后转而执行别的子程序,在适当的时 ...
- Python的异步编程[0] -> 协程[1] -> 使用协程建立自己的异步非阻塞模型
使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为 ...
- 深入理解 Python 异步编程(上)
http://python.jobbole.com/88291/ 前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知 ...
- python 异步编程
Python 3.5 协程究竟是个啥 Yushneng · Mar 10th, 2016 原文链接 : How the heck does async/await work in Python 3.5 ...
- 用 Python 3 的 async / await 做异步编程
前年我曾写过一篇<初探 Python 3 的异步 IO 编程>,当时只是初步接触了一下 yield from 语法和 asyncio 标准库.前些日子我在 V2EX 看到一篇<为什么 ...
- 快速理解Python异步编程的基本原理
第一个例子 假设你需要用电饭煲煮饭,用洗衣机洗衣服,给朋友打电话让他过来吃饭.其中,电饭煲需要30分钟才能把饭煮好,洗衣机需要40分钟才能把衣服洗好,朋友需要50分钟才能到你家.那么,是不是你需要在这 ...
- Python网络编程(4)——异步编程select & epoll
在SocketServer模块的学习中,我们了解了多线程和多进程简单Server的实现,使用多线程.多进程技术的服务端为每一个新的client连接创建一个新的进/线程,当client数量较多时,这种技 ...
- 利用python yielding创建协程将异步编程同步化
转自:http://www.jackyshen.com/2015/05/21/async-operations-in-form-of-sync-programming-with-python-yiel ...
- Atitit.异步编程 java .net php python js 对照
Atitit.异步编程 java .net php python js 的比較 1. 1.异步任务,异步模式, APM模式,, EAP模式, TAP 1 1.1. APM模式: Beg ...
随机推荐
- python地理空间(1)--概念引入
1 python与地理空间分析 1.1 与我们的生活 ushahidi是一个优秀的地理空间地图应用,回寝FQ看一下. ushahidi有一个python库-ushapy 地理空间救灾建模程序是最近比较 ...
- 生产服务GC调优实践基本流程总结
Photo by Pixabay from Pexels 本文作者:夜色微光 - 博客园 (cnblogs.com) 前言 对Java虚拟机进行性能调优是一个非常宽泛的话题,在实践上也是非常棘手的过程 ...
- [uoj173]鏖战表达式
2018年论文题,上接loj2506,主要是论文中的第4章,也可快速跳至原题解 5.平衡树的嵌套问题 平衡树嵌套 所谓平衡树嵌套,就是若干棵平衡树,其中若干棵平衡树的根会指向另一颗平衡树上的一个节点 ...
- [bzoj1109]堆积木
用f[i]表示前i个数,i必须被贡献的答案,考虑转移,枚举下一个被贡献的数j,那么j需要满足:1.$j<i$:2.$a[j]<a[i]$:3.$a[i]-(i-j+1)\le a[j]$, ...
- OAuth 2.1 带来了哪些变化
OAuth 2.1 是 OAuth 2.0 的下一个版本, OAuth 2.1 根据最佳安全实践(BCP), 目前是第18个版本,对 OAuth 2.0 协议进行整合和精简, 移除不安全的授权流程, ...
- SpringCloud升级之路2020.0.x版-41. SpringCloudGateway 基本流程讲解(3)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续分析上一节提到的 WebHandler.加入 Spring Cloud Sleut ...
- 2021年春秋杯网络安全联赛秋季赛 勇者山峰部分wp
1.签到题-Crypto Vigenere 根据题目Vigenere可看出是维吉尼亚密码 使用在线网站破解 https://guballa.de/vigenere-solver flag:53d613 ...
- html中引入外部js文件,使用外部js文件里的方法
外部js文件1: /** * 加了window.onload 后,直接引入js文件即可 * 页面资源全部加载完毕后会自动调用window.onload里的回调函数 */ window.addEvent ...
- 带你了解Typescript的14个基础语法
摘要:Typescript可以说是JavaScript的超集,在JS的基础上新增了许多语法特性,使得类型不再可以随意转换,能大大减少开发阶段的错误. 本文分享自华为云社区<Typescript基 ...
- Codeforces 348C - Subset Sums(根号分治)
题面传送门 对于这类不好直接维护的数据结构,第一眼应该想到-- 根号分治! 我们考虑记[大集合]为大小 \(\geq\sqrt{n}\) 的集合,[小集合]为大小 \(<\sqrt{n}\) 的 ...