一、异步编程概述

异步编程是一种并发编程的模式,其关注点是通过调度不同任务之间的执行和等待时间,通过减少处理器的闲置时间来达到减少整个程序的执行时间;异步编程跟同步编程模型最大的不同就是其任务的切换,当遇到一个需要等待长时间执行的任务的时候,我们可以切换到其他的任务执行;

与多线程和多进程编程模型相比,异步编程只是在同一个线程之内的的任务调度,无法充分利用多核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之异步编程的更多相关文章

  1. Python的异步编程[0] -> 协程[0] -> 协程和 async / await

    协程 / Coroutine 目录 生产者消费者模型 从生成器到异步协程– async/await 协程是在一个线程执行过程中可以在一个子程序的预定或者随机位置中断,然后转而执行别的子程序,在适当的时 ...

  2. Python的异步编程[0] -> 协程[1] -> 使用协程建立自己的异步非阻塞模型

    使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为 ...

  3. 深入理解 Python 异步编程(上)

    http://python.jobbole.com/88291/ 前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知 ...

  4. python 异步编程

    Python 3.5 协程究竟是个啥 Yushneng · Mar 10th, 2016 原文链接 : How the heck does async/await work in Python 3.5 ...

  5. 用 Python 3 的 async / await 做异步编程

    前年我曾写过一篇<初探 Python 3 的异步 IO 编程>,当时只是初步接触了一下 yield from 语法和 asyncio 标准库.前些日子我在 V2EX 看到一篇<为什么 ...

  6. 快速理解Python异步编程的基本原理

    第一个例子 假设你需要用电饭煲煮饭,用洗衣机洗衣服,给朋友打电话让他过来吃饭.其中,电饭煲需要30分钟才能把饭煮好,洗衣机需要40分钟才能把衣服洗好,朋友需要50分钟才能到你家.那么,是不是你需要在这 ...

  7. Python网络编程(4)——异步编程select & epoll

    在SocketServer模块的学习中,我们了解了多线程和多进程简单Server的实现,使用多线程.多进程技术的服务端为每一个新的client连接创建一个新的进/线程,当client数量较多时,这种技 ...

  8. 利用python yielding创建协程将异步编程同步化

    转自:http://www.jackyshen.com/2015/05/21/async-operations-in-form-of-sync-programming-with-python-yiel ...

  9. Atitit.异步编程 java .net php python js 对照

    Atitit.异步编程 java .net php python js 的比較 1. 1.异步任务,异步模式,  APM模式,,  EAP模式, TAP 1 1.1.       APM模式: Beg ...

随机推荐

  1. [hdu6997]愿望幽灵

    约定:$[x^{n}]F(x)$​​​​​​表示多项式$F$​​​​​​的$n$​​​​​​次项系数 对于多项式$F$​​​​​​,定义$F$​​​​​的复合逆$\hat{F}$​​​​​为满足$F( ...

  2. 【TcaplusDB知识库】如何部署TcaplusDB Local 版

    [TcaplusDB知识库]部署TcaplusDB Local 版的准备操作 1. 版本介绍 TcaplusDB Local版,是为用户提供的一个满足本地开发调试的版本(基于Docker部署的可下载版 ...

  3. 列生成算法(求解Cutting Stock问题)

    列生成是用于求解大规模线性优化问题的一种算法,其实就是单纯形法的一种形式.单纯性可以通过不断迭代,通过换基变量的操作,最终找到问题的最优解.但是当问题的规模很大之后,变量的个数就会增大到在有限时间内无 ...

  4. nginx安装与配置4-负载均衡

    负载均衡: 1.准备俩tomcat,测试环境端口不一样,然后服务名一样然后内容不一样 2.配置nginx的config 在http模块中设置: //举例,以下IP,端口无效 upstream test ...

  5. 寒武纪加速平台(MLU200系列) 摸鱼指南(四)--- 边缘端实例程序分析

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  6. HelloWorld与java运行机制

    HelloWorld 新建文件夹存放代码 新建一个java文件 文件后缀为.java Hello.java 注意文件拓展名改为java文件 编写代码 public class Hello{ #类名 p ...

  7. 9.1 k8s pod版本更新流程及命令行实现升级与回滚

    1.创建 Deployment root@k8-deploy:~/k8s-yaml/controllers/deployments# vim nginx-deployment.yaml apiVers ...

  8. 洛谷 P5044 - [IOI2018] meetings 会议(笛卡尔树+DP+线段树)

    洛谷题面传送门 一道笛卡尔树的 hot tea. 首先我们考虑一个非常 naive 的区间 DP:\(dp_{l,r}\) 表示区间 \([l,r]\) 的答案,那么我们考虑求出 \([l,r]\) ...

  9. illumina SNP 芯片转基因型矩阵

    一.芯片数据 此次拿到的illumina芯片数据并不是原始的数据,已经经过GenomeStudio软件处理成了finalreport文件,格式如下: 之前没处理过芯片数据,对于这种编码模式(Forwa ...

  10. phpMyAdmin简介及安装

    phpMyAdmin是一个MySQL数据库管理工具,通过Web接口管理数据库方便快捷. Linux系统安装phpMyAdmin phpMyAdmin是一个MySQL数据库管理工具,通过Web接口管理数 ...