赞
踩
协程(Co-routine),也可称为微线程,或非抢占式的多任务子例程,一种用户态的上下文切换技术(通过一个线程实现代码块间的相互切换执行)。在一个线程(协程)中,遇到io等待时间,线程可以利用这个等待时间去做其他事情。
async和await是针对asyncio提供的@asyncio.coroutine的新语法。
携程函数: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())
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
asyncio 模块最大特点就是,只存在一个线程。由于只有一个线程,就不可能多个任务同时运行。asyncio是"多任务合作"模式(cooperative multitasking),允许异步任务交出执行权给其他任务,等到其他任务完成,再收回执行权继续往下执行。
asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
事件循环:去检索一个任务列表的所有任务,并执行所有未执行任务,直至所有任务执行完成。
执行协程函数,必须使用事件循环。
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,将不会再次执行。
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()的结果快了一秒,也即两个任务同时执行了。
官方文档对Future的介绍大致如下:
Future是特殊的低级等待对象,代表异步操作的最终结果。当等待Future对象时,它意味着协程将等待,直到在其他地方解析Future。需要在asyncio中使用将来的对象,以允许将基于回调的代码与async / await一起使用。通常,不需要在应用程序级别的代码中创建Future对象。(感觉有点类似于JS中的Promise)
使用async/await时 会自动创建Future对象。
携程对象并行执行,使用asyncio.wait()同步。
- task = [task1, task2]
- asyncio.run(asyncio.wait(task))
使用协程下载网页。
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视频)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。