Promise、Async/await 原理彻底理解,举个代码栗子分析一下
2023-09-10 05:30:35
好了,前一篇文章中我们讲到了 Promise 和 async/await 的基本用法,Promise 的原理还是比较清晰的,我们就在这里继续学习一下 async/await 的原理。 如果要学习 async/await,首先我们需要知道 generator 和 yield 的用法。
当我们想实现异步并发的效果时,常常想到的就是用多线程。但是,多线程是 Python 的弱点,它的全局性锁(global interpreter lock)在一定程度的并发下会导致很大的开销。所以 Python 推荐使用异步并发(asynchrony)或协程(coroutine)。
generator 函数在 Python 中,generator 函数是一个 yield 的函数。generator 函数返回一个迭代器,迭代器对象实现了 __iter__(iter)和 __next__(next)特殊方法,因此,我们可以通过 __iter__() 或 __next__() 的方式,拿到迭代器的成员对象。
yield 的用法有以下两种:
-
生成器函数yield 的用法 。当我们遍历迭代器时,迭代器对象就会执行 __iter__() 或 __next__() 方法,进而执行 yield 语句,每执行到 yield 语句就中断执行,并且把 yield 后面的内容作为返回值,然后,抛出 Generatorexiton 作为 yield 语句的引发抛出。
-
异步生成器函数的 yield 的用法 。yield 的这种用法类似于 async-await 的结合,除了可以返回一个值外,还可以返回一个 awaitable 对象(包括 awaitable,awaitable 是一个实现了 __await___ 方法的对象)。
async 和 await 的用法
协程和异步生成器函数都需要用 async 作为前缀。协程既可以是带有 async 前缀的 generator 函数,也可以是带有 async 前缀的普通函数。而异步生成器函数必定是带有 async 前缀的 generator 函数。
我们看看 async 和 await 的用方法。协程需要用 await 调用。异步生成器函数既可以使用 await 调用,也可以直接使用 yield 返回。
await 的用法如下:
-
当 await awaitable 时,运行时将切换到 awaitable 中去,直至 awaitable 执行完毕。如果 awaitable 执行结果是值,则 await 表达式返回值是值。如果 awaitable 执行结果是抛出,则 await 表达式就抛出相同的抛出物。
-
如果 await 后面跟的是 awaitable 对象,就会执行 awaitable 对象的 __await___() 方法,当 awaitable 执行结果返回时,就返回 await 表达式。
当我们用 await 调用 yield 后,返回 yield 的值就是 awaited 对象的返回值,并且 yield 语句也继续执行。
async 和 await 非常容易混淆,也是很多人搞混的地方,我们这里就暂时不讲协程和 asyncio 的用法,后续再讲。
我们现在开始讨论 Promise 。
-
定义:Promise 意味着:一旦异步操作执行完成,就处理它。 Promise 的对象通常是一个异步操作的返回值,或者是实现 __await___() 特殊方法的 awaitable 对象。
-
用法: await 句法糖,即它是一个 awaitable 对象。
注意 Promise 和 await 的区别,Promise 是异步操作的返回值或 awaitable 对象,await 是 awaitable 对象的修饰符。
现在讲一点 Python 中的 await 的原理 。
async/await 的原理其实不难理解,它实际上是通过 yield/generator 实现的。
当运行 async 语句时,将创建一个异步生成器函数,这个异步生成器函数是一个协程,它也是一个迭代器。运行 await 语句时,意味着告诉 Python 运行时“在异步生成器函数中运行到异步生成器函数中的 yield 语句时,要切换到 Promise 中去”,一旦 Promise 的异步操作完成后,就返回到 yield 语句中,进而返回 await 表达式的值,此时 await 语句会抛出 Generatorexiton 作为 yield 语句的引发抛出。
你将会发现,它和 yield/generator 的用法极其相似,只是它只能用于协程中,毕竟 await 的用法是“在协程中运行”,且总是返回一个 awaitable 对象。
async/await 和 Promise 是一对双胞胎。 Promise 是异步操作的返回值,await 专门用于从 Promise 中检索返回值,因此才叫 await。
Python 中的 async/await 和 Promise 是一个有趣的技术。
希望通过这篇文章,你已经清楚地掌握了 Promise 和 async/await 的用法和区别,甚至你已经能轻松地翻译出 generator 函数,比如你完全可以轻松理解 async/await 的含义,这是 yield 语句的语法糖,并且你完全可以轻松理解 Promise 的含义,这是异步操作的返回值。