zoukankan      html  css  js  c++  java
  • 06: asyncio

    1.1 asyncio简介

        参考博客:https://www.cnblogs.com/zhaof/p/8490045.html

      1、什么是asyncio?

          1.和我们以前常用的gevent模块相似,asyncio模块也是在Python中实现协程的模块

          2.区别是gevent是第三方库,通过greenlet实现协程,遇到I/O自动切换(自动挡)

          3.asyncio是Python 3.4版本引入的标准库,asycio 需要自己在代码中让出CPU,控制权在自己手上(手动挡)

          4. asyncio是原生协程关键字:Async和Await,它们的底层基于生成器函数

      2、asyncio应用场景

          1. 在程序在执行 IO 密集型任务的时候,程序会因为等待 IO 而阻塞。

          2. 协程遇到io操作而阻塞时,立即切换到别的任务,如果操作完成则进行回调返回执行结果

      3、asyncio的一些关键字的说明

          1. event_loop 事件循环:程序开启一个无限循环,把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数

          2. coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。

          3. task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含了任务的各种状态

          4. future: 代表将来执行或没有执行的任务的结果。它和task上没有本质上的区别

          5. async/await 关键字:python3.5用于定义协程的关键字,async定义一个协程await用于挂起阻塞的异步调用接口

     1.2 asyncio基本使用

      1、定义协程并创建tasks

          1. 在上面带中我们通过async关键字定义一个协程(coroutine),当然协程不能直接运行,需要将协程加入到事件循环loop中

          2. asyncio.get_event_loop:创建一个事件循环,然后使用run_until_complete将协程注册到事件循环,并启动事件循环

          3. 协程对象不能直接运行,在注册事件循环的时候,其实是run_until_complete方法将协程包装成为了一个任务(task)对象.

          4. task对象是Future类的子类,保存了协程运行后的状态,用于未来获取协程的结果

    import asyncio
    import time
    
    # 我们通过async关键字定义一个协程,当然协程不能直接运行,需要将协程加入到事件循环loop中
    async def do_some_work(x):
        print("waiting:", x)
    
    start = time.time()
    
    coroutine = do_some_work(2)
    loop = asyncio.get_event_loop()        # asyncio.get_event_loop:创建一个事件循环
    # 通过loop.create_task(coroutine)创建task,同样的可以通过 asyncio.ensure_future(coroutine)创建task
    task = loop.create_task(coroutine)     # 创建任务, 不立即执行
    loop.run_until_complete(task)         # 使用run_until_complete将协程注册到事件循环,并启动事件循环
    print("Time:",time.time() - start)
    定义一个协程并创建tasks

      2、绑定回调

          1. 绑定回调,在task执行完成的时候可以获取执行的结果,回调的最后一个参数是future对象,通过该对象可以获取协程返回值。

    import asyncio
    import time
    
    # 我们通过async关键字定义一个协程,当然协程不能直接运行,需要将协程加入到事件循环loop中
    async def do_some_work(x):
        print("waiting:", x)
        return "Done after {}s".format(x)
    
    def callback(future):
        print("callback:",future.result())
    
    start = time.time()
    
    coroutine = do_some_work(2)
    loop = asyncio.get_event_loop()        # asyncio.get_event_loop:创建一个事件循环
    # 通过loop.create_task(coroutine)创建task,同样的可以通过 asyncio.ensure_future(coroutine)创建task
    task = loop.create_task(coroutine)     # 创建任务, 不立即执行
    # task = asyncio.ensure_future(coroutine)
    task.add_done_callback(callback)
    # 绑定回调,在task执行完成的时候可以获取执行的结果
    loop.run_until_complete(task)         # 使用run_until_complete将协程注册到事件循环,并启动事件循环
    print("Time:",time.time() - start)
    
    ''' 运行结果
    waiting: 2
    callback: Done after 2s
    Time: 0.0010030269622802734
    '''
    asyncio绑定回调

      3、阻塞和await

          1. 使用async可以定义协程对象,使用await可以针对耗时的操作进行挂起,就像生成器里的yield一样,函数让出控制权。

          2. 协程遇到await,事件循环将会挂起该协程,执行别的协程,直到其他的协程也挂起或者执行完毕,再进行下一个协程的执行

          3. 耗时的操作一般是一些IO操作,例如网络请求,文件读取等。

          4. 我们使用asyncio.sleep函数来模拟IO操作。协程的目的也是让这些IO操作异步化。

    # 普通串行花费7秒
    import time
    def do_some_work(t):
        time.sleep(t)
        print('用了%s秒' % t)
    
    start = time.time()
    coroutine1 = do_some_work(1)
    coroutine2 = do_some_work(2)
    coroutine3 = do_some_work(4)
    print(time.time()-start)
    '''
    用了1秒
    用了2秒
    用了4秒
    7.002151012420654
    '''
    普通串行花费7秒
    # 使用协程并发执行只花费4秒
    import asyncio
    import time
    
    async def do_some_work(x):
        print("Waiting:",x)
        await asyncio.sleep(x)
        return "Done after {}s".format(x)
    
    start = time.time()
    
    coroutine1 = do_some_work(1)
    coroutine2 = do_some_work(2)
    coroutine3 = do_some_work(4)
    
    tasks = [
        asyncio.ensure_future(coroutine1),
        asyncio.ensure_future(coroutine2),
        asyncio.ensure_future(coroutine3)
    ]
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    
    for task in tasks:
        print("Task ret:",task.result())
    
    print("Time:",time.time() - start)
    '''
    Waiting: 1
    Waiting: 2
    Waiting: 4
    Task ret: Done after 1s
    Task ret: Done after 2s
    Task ret: Done after 4s
    Time: 4.0038135051727295
    '''
    使用协程并发执行只花费4秒

      4、协程嵌套

          1. 使用async可以定义协程,协程用于耗时的io操作,我们也可以封装更多的io操作过程

          2. 这样就实现了嵌套的协程,即一个协程中await了另外一个协程,如此连接起来。

         1)协程嵌套写法

    # 1. 使用async可以定义协程,协程用于耗时的io操作,我们也可以封装更多的io操作过程
    # 2. 这样就实现了嵌套的协程,即一个协程中await了另外一个协程,如此连接起来。import asyncio
    import time
    import asyncio
    
    async def do_some_work(x):
        print("waiting:",x)
        await asyncio.sleep(x)
        return "Done after {}s".format(x)
    
    async def main():
        coroutine1 = do_some_work(1)
        coroutine2 = do_some_work(2)
        coroutine3 = do_some_work(4)
        tasks = [
            asyncio.ensure_future(coroutine1),
            asyncio.ensure_future(coroutine2),
            asyncio.ensure_future(coroutine3)
        ]
    
        dones, pendings = await asyncio.wait(tasks)
        for task in dones:
            print("Task ret:", task.result())
    
        # results = await asyncio.gather(*tasks)
        # for result in results:
        #     print("Task ret:",result)
    
    
    start = time.time()
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    print("Time:", time.time() - start)
    '''
    waiting: 1
    waiting: 2
    waiting: 4
    Task ret: Done after 1s
    Task ret: Done after 2s
    Task ret: Done after 4s
    Time: 4.003407716751099
    '''
    协程嵌套 普通写法
    # 或者返回使用asyncio.wait方式挂起协程
    import asyncio
    import time
    
    async def do_some_work(x):
        print("waiting:",x)
        await asyncio.sleep(x)
        return "Done after {}s".format(x)
    
    async def main():
        coroutine1 = do_some_work(1)
        coroutine2 = do_some_work(2)
        coroutine3 = do_some_work(4)
        tasks = [
            asyncio.ensure_future(coroutine1),
            asyncio.ensure_future(coroutine2),
            asyncio.ensure_future(coroutine3)
        ]
        return await asyncio.wait(tasks)
    
    start = time.time()
    
    loop = asyncio.get_event_loop()
    done,pending = loop.run_until_complete(main())
    for task in done:
        print("Task ret:",task.result())
    
    print("Time:", time.time() - start)
    '''
    waiting: 1
    waiting: 2
    waiting: 4
    Task ret: Done after 1s
    Task ret: Done after 2s
    Task ret: Done after 4s
    Time: 4.002181529998779
    '''
    协程嵌套 使用asyncio.wait方式挂起协程
    import time
    import asyncio
    
    async def job(t):            # 使用 async 关键字将一个函数定义为协程
        await asyncio.sleep(t)   # 等待 t 秒, 期间切换执行其他任务
        print('用了%s秒' % t)
    
    async def main(loop):           # 使用 async 关键字将一个函数定义为协程
        tasks = [loop.create_task(job(t)) for t in range(1,3)]  # 创建任务, 不立即执行
        await asyncio.wait(tasks)   # 执行并等待所有任务完成
    
    start = time.time()
    loop = asyncio.get_event_loop()      # 创建一个事件loop
    loop.run_until_complete(main(loop))  # 将事件加入到事件循环loop
    loop.close()                         # 关闭 loop
    
    print(time.time()-start)
    '''
    用了1秒
    用了2秒
    2.0013420581817627
    '''
    协程嵌套 使用列表推导式简写

    111111111111111111111111

  • 相关阅读:
    Opencv 图像矩
    Opencv Convex Hull (凸包)
    Opencv 发现轮廓 findContours
    Opencv Match Template(轮廓匹配)
    python操作mysql数据库的常用方法使用详解
    mongodb数据库集群及sharding分片配置
    mongodb数据库安装及常见操作
    windows下搭建eclipse关于python的开发环境及初始化参数配置
    python环境下使用tab自动补全命令
    ubuntu系统初始化网络及mysql配置
  • 原文地址:https://www.cnblogs.com/xiaonq/p/12870204.html
Copyright © 2011-2022 走看看