python 异步操作async和await

Posted alex1801

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 异步操作async和await相关的知识,希望对你有一定的参考价值。

1、协程Coroutine

协程(Co-routine),也可称为微线程,或非抢占式的多任务子例程,一种用户态的上下文切换技术(通过一个线程实现代码块间的相互切换执行)。在一个线程(协程)中,遇到io等待时间,线程可以利用这个等待时间去做其他事情。

2、async/await

async和await是针对asyncio提供的@asyncio.coroutine的新语法。

2.1、async

携程函数:python3.5之后使用 async def 函数名,定义的函数就叫携程函数。

携程对象:执行携程函数 函数名(),得到的就是携程对象。

注:执行协程函数得到协程对象,函数内部代码不会执行

# python 源码
>>> import asyncio

>>> async def main():
...     print('hello')
...     await asyncio.sleep(1)
...     print('world')

>>> main()
<coroutine object main at 0x1053bb7c8>

>>> asyncio.run(main()) # 执行协程函数内部代码,必须把协程对象交给事件循环处理
hello
world

其中,

asyncio.run(main()) 
等价于:
oop = asyncio.get_event_loop()
loop.run_until_complate(main())

2.2、await

await + 可等待对象(协程对象,Future,Task对象(IO等待))。

等待到对象的返回结果,才会继续执行后续代码。

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at time.strftime('%X')")

    await say_after(1, 'hello')
    #await say_after(1, 'hello')执行完之后,才继续向下执行
    await say_after(2, 'world')

    print(f"finished at time.strftime('%X')")

asyncio.run(main())

输出:

started at 17:13:52
hello
world
finished at 17:13:55

3、asyncio

asyncio 模块最大特点就是,只存在一个线程。由于只有一个线程,就不可能多个任务同时运行。asyncio是"多任务合作"模式(cooperative multitasking),允许异步任务交出执行权给其他任务,等到其他任务完成,再收回执行权继续往下执行。

asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

3.1、asyncio事件循环(python3.6)

事件循环:去检索一个任务列表的所有任务,并执行所有未执行任务,直至所有任务执行完成。

执行协程函数,必须使用事件循环。

import asyncio

async def func1():
    print('协程1')

async def func2():
    print('协程2')

# task可为列表,即任务列表
# task = func1()
task = [func1(), func2()]
# 创建事件循环
loop = asyncio.get_event_loop()
# 添加任务,直至所有任务执行完成
loop.run_until_complete(asyncio.wait(task))
#关闭事件循环
loop.close()
# 事件循环关闭后,再次调用loop,将不会再次执行。

3.2、asyncio事件循环(python3.7)

python3.7省略的手动创建事件循环,可直接用asyncio.run()去执行协程任务。

import asyncio

async def func1():
    print('协程1')

async def func2():
    print('协程2')

task = [func1(), func2()]
# python3.7引入的新特性,不用手动创建事件循环
asyncio.run(task)

3.3、asyncio.create_task()

asyncio.create_task() 作为异步并发运行协程的函数Tasks。

将协程添加到asyncio.create_task()中,则该协程将很快的自动计划运行。

import asyncio

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)
    
async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

    print(f"started at time.strftime('%X')")

    # 两个任务同时执行,直到到所有任务执行完成。
    await task1
    await task2

    print(f"finished at time.strftime('%X')")

输出:

started at 17:14:32
hello
world
finished at 17:14:34

注:比不使用asyncio.create_task()的结果快了一秒,也即两个任务同时执行了。

3.4、asyncio.futures对象

官方文档对Future的介绍大致如下:

Future是特殊的低级等待对象,代表异步操作的最终结果。当等待Future对象时,它意味着协程将等待,直到在其他地方解析Future。需要在asyncio中使用将来的对象,以允许将基于回调的代码与async / await一起使用。通常,不需要在应用程序级别的代码中创建Future对象。(感觉有点类似于JS中的Promise)

使用async/await时 会自动创建Future对象。

3.5、asyncio.wait()

携程对象并行执行,使用asyncio.wait()同步。

task = [task1, task2]
asyncio.run(asyncio.wait(task))

4、应用实例

使用协程下载网页。

import asyncio
import requests
import time


async def result(url):
    res = await request_url(url)
    print(url, res)


async def request_url(url):
    res = requests.get(url)
    print(url)
    await asyncio.sleep(2)
    print("execute_time:", time.time() - start)
    return res


url_list = ["https://www.csdn.net/",
            "https://blog.csdn.net/qq_43380180/article/details/111573642",
            "https://www.baidu.com/",
            ]

start = time.time()
print(f"start_time:start\\n")

task = [result(url) for url in url_list]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task))

endtime = time.time() - start
print("\\nendtime:", time.time())
print("all_execute_time:", endtime)

使用协程时,需要其底层方法实现时就是协程,才会生效,否则协程不生效!

此处使用的requests底层实现并不是异步,因此使用了time.sleep() 和 asyncio.sleep()模拟放大网络IO时间。

以下代码等价:

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task))
等价于:
asyncio.run(asyncio.wait(task))

参考文章:

1、Python 异步 async/await(进阶详解)

https://blog.csdn.net/qq_43380180/article/details/111573642

2、python官方文档介绍(中文)

https://docs.python.org/zh-cn/3.7/library/asyncio-eventloop.html

3、Python异步编程 asyncio小白速通(bilibili视频)

https://www.bilibili.com/video/BV1dD4y127bD/

以上是关于python 异步操作async和await的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot之@Async异步调用

Javascript async异步操作库简介

springboot2.0 异步操作,@Async失效,无法进入异步

研究c#异步操作async await状态机的总结

async/await

研究c#异步操作async await状态机的总结