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 ...
随机推荐
- [hdu7082]Pty loves lcm
先将问题差分,即仅考虑上限$R$(和$L-1$) 注意到$f(x,y)$增长是较快的,对其分类讨论: 1.若$y\ge x+2$,此时满足$f(x,y)\le 10^{18}$的$(x,y)$只有约$ ...
- 【JavaSE】JDK配置
Java开发环境配置 2020-09-10 08:32:20 by冲冲 1. Windows7安装JDK 1.1 下载JDK ① 下载地址:http://www.oracle.com/techne ...
- 爬虫进阶篇(一)scrapy
1.本教程默认认为您已经像我一样是个半吊子爬虫程序员 2.学习爬虫首先要懂得request,json,bs4,re,xpath,pymysql,random,time,文件相关,理解网络编程基本原理, ...
- SpringCloud升级之路2020.0.x版-44.避免链路信息丢失做的设计(1)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们在这一节首先分析下 Spring Cloud Gateway 一些其他可能丢失链路信息 ...
- 洛谷 P3711 - 仓鼠的数学题(多项式)
洛谷题面传送门 提供一种不太一样的做法. 假设要求的多项式为 \(f(x)\).我们考察 \(f(x)-f(x-1)\),不难发现其等于 \(\sum\limits_{i=0}^na_ix^i\) 考 ...
- 【R】write.table输出数据带有行名?
目录 问题 解决一 解决二 问题 这个问题应该很常见吧.R中输出数据框时,想要把行名和列名都输出.如果直接输出的话,输出的结果列名会往前移动一位,这显然不是我们想要的. 直接上例子: > a = ...
- pycharm两个交互模式
- MariaDB—备份数据库
1> 备份单个数据库 mysqldump -uroot -plichao123 --database students1 > stundents.sql; 2>查看备份文件 3> ...
- Excel—在Excel中利用宏定义实现MD5对字符串(如:手机号)或者文件加密
下载宏文件[md5宏] 加载宏 试验md5加密 可能遇到的问题 解决办法 下载宏文件[md5宏] 下载附件,解压,得md5宏.xla md5宏.zip 加载宏 依次打开[文件]-[选项]-[自定义功能 ...
- PL\SQL和PL/SQL Developer 12安装与配置
安装: (1)在已有安装包的情况下,直接将安装包解压到文件夹下,注意不要解压缩到c:\programs Files(x86)的文件夹下,不能解压缩到有中文文件夹命名的文件夹下面 (2)没有安装包的情况 ...