当前位置:   article > 正文

python 异步操作async和await_python async

python async

1、协程Coroutine

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

2、async/await

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

2.1、async

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

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

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

  1. # python 源码
  2. >>> import asyncio
  3. >>> async def main():
  4. ... print('hello')
  5. ... await asyncio.sleep(1)
  6. ... print('world')
  7. >>> main()
  8. <coroutine object main at 0x1053bb7c8>
  9. >>> asyncio.run(main()) # 执行协程函数内部代码,必须把协程对象交给事件循环处理
  10. hello
  11. world

其中,

  1. asyncio.run(main())
  2. 等价于:
  3. oop = asyncio.get_event_loop()
  4. loop.run_until_complate(main())

2.2、await

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

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

  1. import asyncio
  2. import time
  3. async def say_after(delay, what):
  4. await asyncio.sleep(delay)
  5. print(what)
  6. async def main():
  7. print(f"started at {time.strftime('%X')}")
  8. await say_after(1, 'hello')
  9. #await say_after(1, 'hello')执行完之后,才继续向下执行
  10. await say_after(2, 'world')
  11. print(f"finished at {time.strftime('%X')}")
  12. asyncio.run(main())

输出:

  1. started at 17:13:52
  2. hello
  3. world
  4. finished at 17:13:55

3、asyncio

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

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

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

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

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

  1. import asyncio
  2. async def func1():
  3. print('协程1')
  4. async def func2():
  5. print('协程2')
  6. # task可为列表,即任务列表
  7. # task = func1()
  8. task = [func1(), func2()]
  9. # 创建事件循环
  10. loop = asyncio.get_event_loop()
  11. # 添加任务,直至所有任务执行完成
  12. loop.run_until_complete(asyncio.wait(task))
  13. #关闭事件循环
  14. loop.close()
  15. # 事件循环关闭后,再次调用loop,将不会再次执行。

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

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

  1. import asyncio
  2. async def func1():
  3. print('协程1')
  4. async def func2():
  5. print('协程2')
  6. task = [func1(), func2()]
  7. # python3.7引入的新特性,不用手动创建事件循环
  8. asyncio.run(task)

3.3、asyncio.create_task()

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

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

  1. import asyncio
  2. async def say_after(delay, what):
  3. await asyncio.sleep(delay)
  4. print(what)
  5. async def main():
  6. task1 = asyncio.create_task(
  7. say_after(1, 'hello'))
  8. task2 = asyncio.create_task(
  9. say_after(2, 'world'))
  10. print(f"started at {time.strftime('%X')}")
  11. # 两个任务同时执行,直到到所有任务执行完成。
  12. await task1
  13. await task2
  14. print(f"finished at {time.strftime('%X')}")

输出:

  1. started at 17:14:32
  2. hello
  3. world
  4. 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()同步。

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

4、应用实例

使用协程下载网页。

  1. import asyncio
  2. import requests
  3. import time
  4. async def result(url):
  5. res = await request_url(url)
  6. print(url, res)
  7. async def request_url(url):
  8. res = requests.get(url)
  9. print(url)
  10. await asyncio.sleep(2)
  11. print("execute_time:", time.time() - start)
  12. return res
  13. url_list = ["https://www.csdn.net/",
  14. "https://blog.csdn.net/qq_43380180/article/details/111573642",
  15. "https://www.baidu.com/",
  16. ]
  17. start = time.time()
  18. print(f"start_time:{start}\n")
  19. task = [result(url) for url in url_list]
  20. loop = asyncio.get_event_loop()
  21. loop.run_until_complete(asyncio.wait(task))
  22. endtime = time.time() - start
  23. print("\nendtime:", time.time())
  24. print("all_execute_time:", endtime)

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

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

以下代码等价:

  1. loop = asyncio.get_event_loop()
  2. loop.run_until_complete(asyncio.wait(task))
  3. 等价于:
  4. 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/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/703693
推荐阅读
相关标签
  

闽ICP备14008679号