Python协程是一种基于生成器的异步编程模型,允许在单线程中实现代码块的相互切换执行。在Python中,协程对象是一种特殊的可等待对象,它实现了__await__()方法,可以使用async/await语法来编写异步代码。此外,还可以通过定义异步迭代器和异步上下文管理器来实现更复杂的异步操作。
一、可等待对象
awaitable 对象主要实现了 __await__() 方法。 从 async def 函数返回的 协程对象 即为可等待对象。从带有 types.coroutine() 装饰器的生成器返回的 generator iterator 对象也属于可等待对象,但它们并未实现 __await__()。
在 asyncio 模块中,awaitable 对象应当实现 __await__() 方法,而该方法必须返回一个迭代器(iterator)。这个迭代器会被用于执行异步操作,并在必要时暂停和恢复执行状态。
为了与 await 表达式相兼容,__await__() 方法通常会在其中包含一个生成器(generator)。它可以通过使用 yield 语句来暂停执行,并通过返回适当的值来恢复执行。这使得 awaitable 对象能够在需要等待其他协程完成时暂停执行,并在获取结果后继续执行。
二、协程对象
协程对象是 awaitable 对象的一种具体实现。我们可以通过调用协程对象的 __await__() 方法并迭代其结果来控制协程的执行。当协程执行完毕并返回时,迭代器会引发 StopIteration 异常,并且该异常的 value 属性将存放协程的返回值。这样,在使用 for-in 循环或调用 next() 进行迭代时,我们可以获取到协程的返回值。在协程执行过程中,如果协程引发了异常,该异常会被迭代器传播出去,从而可以对协程中的异常进行适当的处理。
协程也具有下面列出的方法,它们类似于生成器的对应方法 (参见 生成器-迭代器的方法)。 但是,与生成器不同,协程并不直接支持迭代。
coroutine.send(value)
开始或恢复协程的执行。 如果 value 为 None,那么这就相当于前往 __await__() 所返回迭代器的下一项。 如果 value 不为 None,此方法将委托给导致协程挂起的迭代器的 send() 方法。 其结果(返回值,StopIteration 或是其他异常)将与上述对 __await__() 返回值进行迭代的结果相同。
coroutine.throw(value) coroutine.throw(type[, value[, traceback]])
在协程内引发指定的异常。 此方法将委托给导致该协程挂起的迭代器的 throw() 方法,如果存在此方法的话。 否则,该异常将在挂起点被引发。 其结果(返回值,StopIteration 或是其他异常)将与上述对 __await__() 返回值进行迭代的结果相同。 如果该异常未在协程内被捕获,则将回传给调用方。
coroutine.close()
此方法会使得协程清理自身并退出。 如果协程被挂起,此方法会先委托给导致协程挂起的迭代器的 close() 方法,如果存在该方法。 然后它会在挂起点引发 GeneratorExit,使得协程立即清理自身。 最后,协程会被标记为已结束执行,即使它根本未被启动。当协程对象将要被销毁时,会使用以上处理过程来自动关闭。
三、异步迭代器
异步迭代器可以在其 __anext__() 方法中调用异步代码。异步迭代器是一种特殊类型的迭代器,它允许在迭代过程中执行异步操作。在异步迭代器中,我们可以在 __anext__() 方法中使用 await 关键字来等待异步操作的结果。
object.__aiter__(self)
以上代码表示必须返回一个 异步迭代器 对象。
object.__anext__(self)
以上代码表示必须返回一个 可迭代对象 输出迭代器的下一结果值。 当迭代结束时应该引发 StopAsyncIteration 错误。
异步可迭代对象的一个示例:
class Reader: async def readline(self): ... def __aiter__(self): return self async def __anext__(self): val = await self.readline() if val == b'': raise StopAsyncIteration return val
- 在 3.7 版更改: 在 Python 3.7 之前,__aiter__() 可以返回一个 可等待对象 并将被解析为 异步迭代器。
- 从 Python 3.7 开始,__aiter__() 必须返回一个异步迭代器对象。 返回任何其他对象都将导致 TypeError 错误。
四、异步上下文管理器
异步上下文管理器可以在 async with 语句中使用,这样可以更加方便地使用和管理异步资源。
异步上下文管理器是上下文管理器的一种,它允许在其 __aenter__() 和 __aexit__() 方法中执行异步操作,并暂停执行。与普通的上下文管理器不同,异步上下文管理器可以在 __aenter__() 方法中使用 await 关键字来等待异步操作的结果,并在 __aexit__() 方法中执行异步清理代码。这使得我们可以在异步环境中方便地管理资源,并确保资源能够正确地被释放或关闭。
object.__aenter__(self)
以上代码表示在语义上类似于 __enter__(),仅有的区别是它必须返回一个 可等待对象。
object.__aexit__(self, exc_type, exc_value, traceback)
以上代码表示在语义上类似于 __exit__(),仅有的区别是它必须返回一个 可等待对象。
异步上下文管理器类的一个示例:
class AsyncContextManager: async def __aenter__(self): await log('entering context') async def __aexit__(self, exc_type, exc, tb): await log('exiting context')