详解python之异步编程

 更新时间:2021年12月24日 08:54:03   作者:Python_xiaowu  
这篇文章主要为大家介绍了python之异步编程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助<BR>

一、异步编程概述

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

与多线程和多进程编程模型相比,异步编程只是在同一个线程之内的的任务调度,无法充分利用多核CPU的优势,所以特别适合IO阻塞性任务;

python 版本 3.9.5

二、python的异步框架模型

python提供了asyncio模块来支持异步编程,其中涉及到coroutinesevent loopsfutures三个重要概念;

event loops主要负责跟踪和调度所有异步任务,编排具体的某个时间点执行的任务;

coroutines是对具体执行任务的封装,是一个可以在执行中暂停并切换到event loops执行流程的特殊类型的函数;其一般还需要创建task才能被event loops调度;

futures负责承载coroutines的执行结果,其随着任务在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在语法上提供了asyncawait两个关键字来简化将同步代码修改为异步;

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编写简单的端口扫描器的实例分享

    这篇文章主要介绍了使用Python编写简单的端口扫描器的实例分享,文中分别介绍了单线程和多线程的实现方式,需要的朋友可以参考下
    2015-12-12
  • python + pyqt5制作一个串口助手

    python + pyqt5制作一个串口助手

    这篇文章主要介绍了python + pyqt5制作一个串口助手,串口助手是串口通信使用的工具,为整合知识,打算做个串口助手,本文给大家讲解的非常详细,需要的朋友可以参考下
    2023-04-04
  • python绘制地震散点图

    python绘制地震散点图

    这篇文章主要为大家详细介绍了python绘制地震散点图的相关方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-06-06
  • 关于python列表增加元素的三种操作方法

    关于python列表增加元素的三种操作方法

    这篇文章主要介绍了关于python列表增加元素的几种操作方法,主要有insert方法,extend方法和append方法,每种方法给大家介绍的非常详细,需要的朋友可以参考下
    2018-08-08
  • 使用opencv中匹配点对的坐标提取方式

    使用opencv中匹配点对的坐标提取方式

    这篇文章主要介绍了使用opencv中匹配点对的坐标提取方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • VSCode配置Anaconda Python环境的实现

    VSCode配置Anaconda Python环境的实现

    VisualStudioCode中可以使用Anaconda环境进行Python开发,本文主要介绍了VSCode配置Anaconda Python环境的实现,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • 使用Python自定义创建的Log日志模块

    使用Python自定义创建的Log日志模块

    这篇文章主要介绍了使用Python自定义创建的Log日志模块,日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用,需要的朋友可以参考下
    2023-07-07
  • Python基于Google Bard实现交互式聊天机器人

    Python基于Google Bard实现交互式聊天机器人

    这篇文章主要为大家介绍了Python基于Google Bard实现交互式聊天机器人示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • python中如何使用正则表达式的非贪婪模式示例

    python中如何使用正则表达式的非贪婪模式示例

    贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,下面这篇文章主要给大家介绍了关于python中如何使用正则表达式的非贪婪模式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-10-10
  • Python开发之城堡保卫战游戏的实现

    Python开发之城堡保卫战游戏的实现

    这篇文章主要为大家详细介绍了如何利用Python编写一个简单的城堡保卫战游戏,本文用到了os文件读写,pygame模块以及面向对象思想,感兴趣的可以了解一下
    2023-01-01

最新评论