Python并发之异步I/O(async,await)
前面关于yield,yield from的语法说了好多,其实大多是铺垫,算是python在通往异步大道上的一些探索,但是将异步完整融入python整个过程并非都是顺利的,创建修改替换修改,反反复复,直到最新几版的python,趋于平稳,用其优雅特性来给人们展示异步,我们一起来看看!
1. 背景
Python有很长一段的异步编程历史,特别是twisted
,gevent
和一些无堆栈的Python项目。
异步编程因为一些好的原因在这些年来越来越受关注。尽管相对于传统的线性风格更难一点,但是却是值得的:因为异步编程有更高的效率。
举个例子:在Http请求方面,Python异步协程可以提交请求然后去做队列中其他等待的任务,让它慢慢请求,而不是传统的一直等它请求到完成为止,这样的话会浪费更多的时间与资源。总之异步编程能让你的代码在处于等待资源状态时处理其他任务。
在Python3.4中,asyncio
产生了。而在Python3.5中,有加入了对async def
和await
新的语法支持。
2. 四个核心概念
2.1 Eventloop
Eventloop 可以说是 asyncio 应用的核心,是中央总控。Eventloop 实例提供了注册、取消和执行任务和回调的方法。
把一些异步函数 (就是任务,Task,一会就会说到) 注册到这个事件循环上,事件循环会循环执行这些函数 (但同时只能执行一个),当执行到某个函数时,如果它正在等待 I/O 返回,事件循环会暂停它的执行去执行其他的函数;当某个函数完成 I/O 后会恢复,下次循环到它的时候继续执行。因此,这些异步函数可以协同 (Cooperative) 运行:这就是事件循环的目标。
2.2 Coroutine
协程 (Coroutine) 本质上是一个函数,特点是在代码块中可以将执行权交给其他协程:
1 |
|
asyncio.gather 用来并发运行任务,在这里表示协同的执行 a 和 b两个协程
在协程 a 中,有一句 await asyncio.sleep (0),await 表示调用协程,sleep 0 并不会真的 sleep(因为时间为 0),但是却可以把控制权交出去了。
2.3 Future
接着说 Future,它代表了一个「未来」对象,异步操作结束后会把最终结果设置到这个 Future 对象上。Future 是对协程的封装,不过日常开发基本是不需要直接用这个底层 Future 类的
2.4 Task
Eventloop 除了支持协程,还支持注册 Future 和 Task2 种类型的对象,那为什么要存在 Future 和 Task 这 2 种类型呢?
Future 是协程的封装,Future 对象提供了很多任务方法 (如完成后的回调、取消、设置任务结果等等),但是开发者并不需要直接操作 Future 这种底层对象,而是用 Future 的子类 Task 协同的调度协程以实现并发。
Task 非常容易创建和使用:
1 |
|
在这边的时候我卡了很长时间:future与Task的区别是什么????
future在多线程说过,future表示终将发生的事情,而确定某件事会发生的唯一方式是执行的时间已经排定。(你不排定它,它就是个协程),那怎么排定?
BaseEventLoop.create_task(…) 或者 asyncio.ensure_future方法接收一个协程,排定它的运行时间,然后返回一个asyncio.Task 实例——也是 asyncio.Future 类的实例,因为 Task 是Future 的子类,用于包装协程。这与调用 Executor.submit(…) 方法创建Future实例是一个道理
这句话我读了好多遍,意思是不是说future跟task是同一样东西。对于event loop来说,一个包装了协程的future,就是循环中的一个task?我是这么理解的。
我们无法确定future啥时完成结束,但是总归结束(无论报错还是返回值)的,因为我们已经给它排定了时间。
3. 如何准确使用asyncio
自从Python3.5加入了async def
和await
新的语法,在往后Python大版本更新中一直对该部分的语法有更新修改,从前期的乱而杂,到最新的Python3.8语法渐渐稳定下来,优雅了很多,文档也条理了很多,其实要使用真正的语法还是要多看看官网例子。
初阶选手使用时,一般的High-level APIs
完全可以满足需求,当理解了高阶API时,在去查看源代码,查看Low-level APIs
,深层次的理解!这里有个较新的教程,分三个部分,很好!,推荐阅读!
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!