实例分析asyncio实现python异步任务

实例分析asyncio实现python异步任务

1.分析对象asyncio

asyncio包是python之父Guido在python仓库之外开发的一个库,其作用是使用事件循环驱动的协程实现并发。asyncio类型的事件驱动框架的运作方式为:在单个线程中使用一个主循环驱动协程执行并发活动,使用协程进行并发编程时,协程会不断把控制权让步给主循环,激活并向前运行其他协程,从而执行各个并发活动。

2.了解yield from句法

yield from:asyncio包中使用了大量的yield from语句,可以说yield from句法的特性是asyncio包实现异步调度线程的最大功臣。把职责委托给子生成器的句法,使用它可以把复杂的生成器重构成小型的嵌套生成器,省去了之前把生产器的工作委托给子生成器所需的大量样本代码。在协程中,yield from的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起来,这样二者可以直接发送和产出值,还可以直接传入异常,而不用在位于中间的协程中添加大量处理异常的样板代码。有了这个结构,协程可以通过以前不可能的方式委托职责。以下是在协程中使用yield from语句需要了解的新的术语:

  • 委派生成器
    • 包含yield from表达式的生成器函数,委派生成器在yield from表达式处暂停时,调用方可以直接把数据发给子生成器,子生成器再把产出的值发给调用法。子生成器返回之后,解释器会抛出StopIteration异常,并把返回值附加在异常对象上,此时委派生成器会恢复
  • 子生成器:
    • 从yield from表达式中部分获取的生成器。
  • 调用方
    • 委派生成器的客户端代码

如果你想要具体了解协程,可访问此链接:https://blog.csdn.net/jasonzhoujx/article/details/81506303

3.实例源码

import asyncio
import sys
import itertools

#使用@asyncio.coroutine装饰器不是强制要求,但强烈建议这么做,因为这样可以在一众普通函数中把协程凸显出#来,也有助于调试
@asyncio.coroutine
def slow_down():
    # 假装等待I/O一段时间
    yield from asyncio.sleep(3)
    return 42

@asyncio.coroutine
def spin(msg):
    write, flush = sys.stdout.write, sys.stdout.flush
    #cycle()迭代器能够不停的反复依次产生'|/-\\'字符,其中第一个\为转义字符
    for char in itertools.cycle('|/-\\'):
        status = char + ' ' + msg
        write(status)
        #刷新输出
        flush()
        #uncoded'\x08'为空格标志,这里作用是使用空格清楚状态信息,把光标移回开头
        write('\x08' * len(status))
        try:
            #执行这条语句是spin函数暂停等待asyncio.sleep()运行结束
            yield from asyncio.sleep(.01)
        except asyncio.CancelledError:
            break
    write(' '* len(status) + '\x08' * len(status))

@asyncio.coroutine
def supervisor():
    #asyncio.async()方法会为协程spin()排定运行时间,即将其包装成一个Task对象
    spinner = asyncio.async(spin('thinking!'))
    #todo spin(msg),不断刷新旋转条
    print('spinner object: ', spinner)
    #当运行到yield from时,supervisor协程会停止运行,将控制权还给其调用者,只作为main函数
    #和slow_down()函数的通信的管道,当slow_down()运行结束,supervisor函数恢复运行
    result = yield from slow_down()
    spinner.cancel()
    return result

def main():
    #获取事件循环的引用 
    loop = asyncio.get_event_loop()
    #asyncio.run_until_complete()方法能够驱动supervisor函数运行直至结束
    result = loop.run_until_complete(supervisor())
    #关闭事件循环
    loop.close()
    print('Answer: ', result)

if __name__ == '__main__':
    main()

4.运行过程

  • 使用asyncio.get_event_loop()初始化一个支持异步调度的事件循环;
  • 然后使用事件循环的run_until_complete()去驱动supervisor(),这里返回的result是一个已经对superviror()排定执行时间的Task对象;
  • supervisor()中又利用asyncio.async()方法驱动协程spin,同样返回的spinner也是一个已经对spin()协程排定执行时间的Task对象
  • 运行yield from slow_down()函数时supervisor是处于暂停状态,但是spinner和slow_down()都处于并发运行的状态,当slow_down()函数执行的等待3秒结束后,supervisor恢复运行,进而结束spinner协程。
  • supervisor()协程运行结束,main()中的事件循环得到回调,因为这里事件循环中只有一个事件,于是得到回调的loop运行结束,接着关闭事件循环。
  • 程序运行结束

猜你喜欢

转载自blog.csdn.net/jasonzhoujx/article/details/81556807