Python協程是一種基于生成器的異步編程模型,允許在單線程中實現代碼塊的相互切換執(zhí)行。在Python中,協程對象是一種特殊的可等待對象,它實現了__await__()方法,可以使用async/await語法來編寫異步代碼。此外,還可以通過定義異步迭代器和異步上下文管理器來實現更復雜的異步操作。
一、可等待對象
awaitable 對象主要實現了 __await__() 方法。 從 async def 函數返回的 協程對象 即為可等待對象。從帶有 types.coroutine() 裝飾器的生成器返回的 generator iterator 對象也屬于可等待對象,但它們并未實現 __await__()。
在 asyncio 模塊中,awaitable 對象應當實現 __await__() 方法,而該方法必須返回一個迭代器(iterator)。這個迭代器會被用于執(zhí)行異步操作,并在必要時暫停和恢復執(zhí)行狀態(tài)。
為了與 await 表達式相兼容,__await__() 方法通常會在其中包含一個生成器(generator)。它可以通過使用 yield 語句來暫停執(zhí)行,并通過返回適當的值來恢復執(zhí)行。這使得 awaitable 對象能夠在需要等待其他協程完成時暫停執(zhí)行,并在獲取結果后繼續(xù)執(zhí)行。
二、協程對象
協程對象是 awaitable 對象的一種具體實現。我們可以通過調用協程對象的 __await__() 方法并迭代其結果來控制協程的執(zhí)行。當協程執(zhí)行完畢并返回時,迭代器會引發(fā) StopIteration 異常,并且該異常的 value 屬性將存放協程的返回值。這樣,在使用 for-in 循環(huán)或調用 next() 進行迭代時,我們可以獲取到協程的返回值。在協程執(zhí)行過程中,如果協程引發(fā)了異常,該異常會被迭代器傳播出去,從而可以對協程中的異常進行適當的處理。
協程也具有下面列出的方法,它們類似于生成器的對應方法 (參見 生成器-迭代器的方法)。 但是,與生成器不同,協程并不直接支持迭代。
coroutine.send(value)
開始或恢復協程的執(zhí)行。 如果 value 為 None,那么這就相當于前往 __await__() 所返回迭代器的下一項。 如果 value 不為 None,此方法將委托給導致協程掛起的迭代器的 send() 方法。 其結果(返回值,StopIteration 或是其他異常)將與上述對 __await__() 返回值進行迭代的結果相同。
coroutine.throw(value) coroutine.throw(type[, value[, traceback]])
在協程內引發(fā)指定的異常。 此方法將委托給導致該協程掛起的迭代器的 throw() 方法,如果存在此方法的話。 否則,該異常將在掛起點被引發(fā)。 其結果(返回值,StopIteration 或是其他異常)將與上述對 __await__() 返回值進行迭代的結果相同。 如果該異常未在協程內被捕獲,則將回傳給調用方。
coroutine.close()
此方法會使得協程清理自身并退出。 如果協程被掛起,此方法會先委托給導致協程掛起的迭代器的 close() 方法,如果存在該方法。 然后它會在掛起點引發(fā) GeneratorExit,使得協程立即清理自身。 最后,協程會被標記為已結束執(zhí)行,即使它根本未被啟動。當協程對象將要被銷毀時,會使用以上處理過程來自動關閉。
三、異步迭代器
異步迭代器可以在其 __anext__() 方法中調用異步代碼。異步迭代器是一種特殊類型的迭代器,它允許在迭代過程中執(zhí)行異步操作。在異步迭代器中,我們可以在 __anext__() 方法中使用 await 關鍵字來等待異步操作的結果。
object.__aiter__(self)
以上代碼表示必須返回一個 異步迭代器 對象。
object.__anext__(self)
以上代碼表示必須返回一個 可迭代對象 輸出迭代器的下一結果值。 當迭代結束時應該引發(fā) 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__() 方法中執(zhí)行異步操作,并暫停執(zhí)行。與普通的上下文管理器不同,異步上下文管理器可以在 __aenter__() 方法中使用 await 關鍵字來等待異步操作的結果,并在 __aexit__() 方法中執(zhí)行異步清理代碼。這使得我們可以在異步環(huán)境中方便地管理資源,并確保資源能夠正確地被釋放或關閉。
object.__aenter__(self)
以上代碼表示在語義上類似于 __enter__(),僅有的區(qū)別是它必須返回一個 可等待對象。
object.__aexit__(self, exc_type, exc_value, traceback)
以上代碼表示在語義上類似于 __exit__(),僅有的區(qū)別是它必須返回一個 可等待對象。
異步上下文管理器類的一個示例:
class AsyncContextManager: async def __aenter__(self): await log('entering context') async def __aexit__(self, exc_type, exc, tb): await log('exiting context')