• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

python:异步编程

武飞扬头像
代码输入中...
帮助1

一、异步编程概述

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

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

三、顺序执行多个可重叠的任务

每个任务执行中间会暂停给定的时间,循序执行的时间就是每个任务执行的时间加和;

  1.  
    import time
  2.  
     
  3.  
    def count_down(name, delay):
  4.  
    indents = (ord(name) - ord('A')) * '\t'
  5.  
     
  6.  
    n = 3
  7.  
    while n:
  8.  
    time.sleep(delay)
  9.  
    duration = time.perf_counter() - start
  10.  
    print('-' * 40)
  11.  
    print(f'{duration:.4f} \t{indents}{name} = {n}')
  12.  
    n -= 1
  13.  
     
  14.  
     
  15.  
    start = time.perf_counter()
  16.  
     
  17.  
    count_down('A', 1)
  18.  
    count_down('B', 0.8)
  19.  
    count_down('C', 0.5)
  20.  
    print('-' * 40)
  21.  
    print('Done')
  22.  
     
  23.  
    # ----------------------------------------
  24.  
    # 1.0010 A = 3
  25.  
    # ----------------------------------------
  26.  
    # 2.0019 A = 2
  27.  
    # ----------------------------------------
  28.  
    # 3.0030 A = 1
  29.  
    # ----------------------------------------
  30.  
    # 3.8040 B = 3
  31.  
    # ----------------------------------------
  32.  
    # 4.6050 B = 2
  33.  
    # ----------------------------------------
  34.  
    # 5.4059 B = 1
  35.  
    # ----------------------------------------
  36.  
    # 5.9065 C = 3
  37.  
    # ----------------------------------------
  38.  
    # 6.4072 C = 2
  39.  
    # ----------------------------------------
  40.  
    # 6.9078 C = 1
  41.  
    # ----------------------------------------
  42.  
    # 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;

  1.  
    async def count_down(name, delay, start):
  2.  
    indents = (ord(name) - ord('A')) * '\t'
  3.  
     
  4.  
    n = 3
  5.  
    while n:
  6.  
    await asyncio.sleep(delay)
  7.  
    duration = time.perf_counter() - start
  8.  
    print('-' * 40)
  9.  
    print(f'{duration:.4f} \t{indents}{name} = {n}')
  10.  
    n -= 1

我们定义一个异步的main方法,主要完成task的创建和等待任务执行结束;

  1.  
    async def main():
  2.  
    start = time.perf_counter()
  3.  
    tasks = [asyncio.create_task(count_down(name,delay,start)) for name, delay in [('A', 1),('B', 0.8),('C', 0.5)]]
  4.  
    await asyncio.wait(tasks)
  5.  
    print('-' * 40)
  6.  
    print('Done')

执行我们可以看到时间已经变为了执行时间最长的任务的时间了;

  1.  
    asyncio.run(main())
  2.  
     
  3.  
    # ----------------------------------------
  4.  
    # 0.5010 C = 3
  5.  
    # ----------------------------------------
  6.  
    # 0.8016 B = 3
  7.  
    # ----------------------------------------
  8.  
    # 1.0011 A = 3
  9.  
    # ----------------------------------------
  10.  
    # 1.0013 C = 2
  11.  
    # ----------------------------------------
  12.  
    # 1.5021 C = 1
  13.  
    # ----------------------------------------
  14.  
    # 1.6026 B = 2
  15.  
    # ----------------------------------------
  16.  
    # 2.0025 A = 2
  17.  
    # ----------------------------------------
  18.  
    # 2.4042 B = 1
  19.  
    # ----------------------------------------
  20.  
    # 3.0038 A = 1
  21.  
    # ----------------------------------------
  22.  
    # Done
学新通

五、使用多线程克服具体任务的异步限制

异步编程要求具体的任务必须是coroutine,也就是要求方法是异步的,否则只有任务执行完了,才能将控制权释放给event loop;

python中的concurent.futures提供了ThreadPoolExecutor和ProcessPoolExecutor,可以直接在异步编程中使用,从而可以在单独的线程或者进程至今任务;

  1.  
    import time
  2.  
    import asyncio
  3.  
    from concurrent.futures import ThreadPoolExecutor
  4.  
     
  5.  
    def count_down(name, delay, start):
  6.  
    indents = (ord(name) - ord('A')) * '\t'
  7.  
     
  8.  
    n = 3
  9.  
    while n:
  10.  
    time.sleep(delay)
  11.  
     
  12.  
    duration = time.perf_counter() - start
  13.  
    print('-'*40)
  14.  
    print(f'{duration:.4f} \t{indents}{name} = {n}')
  15.  
    n -=1
  16.  
     
  17.  
    async def main():
  18.  
    start = time.perf_counter()
  19.  
    loop = asyncio.get_running_loop()
  20.  
    executor = ThreadPoolExecutor(max_workers=3)
  21.  
    fs = [
  22.  
    loop.run_in_executor(executor, count_down, *args) for args in [('A', 1, start), ('B', 0.8, start), ('C', 0.5, start)]
  23.  
    ]
  24.  
     
  25.  
    await asyncio.wait(fs)
  26.  
    print('-'*40)
  27.  
    print('Done.')
  28.  
     
  29.  
    asyncio.run(main())
  30.  
     
  31.  
    # ----------------------------------------
  32.  
    # 0.5087 C = 3
  33.  
    # ----------------------------------------
  34.  
    # 0.8196 B = 3
  35.  
    # ----------------------------------------
  36.  
    # 1.0073 A = 3
  37.  
    # ----------------------------------------
  38.  
    # 1.0234 C = 2
  39.  
    # ----------------------------------------
  40.  
    # 1.5350 C = 1
  41.  
    # ----------------------------------------
  42.  
    # 1.6303 B = 2
  43.  
    # ----------------------------------------
  44.  
    # 2.0193 A = 2
  45.  
    # ----------------------------------------
  46.  
    # 2.4406 B = 1
  47.  
    # ----------------------------------------
  48.  
    # 3.0210 A = 1
  49.  
    # ----------------------------------------
  50.  
    # Done.
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfeaeg
系列文章
更多 icon
同类精品
更多 icon
继续加载