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的主要内容,如果未能解决你的问题,请参考以下文章