隨着asyncio
庫我見過,@ asyncio.coroutine VS異步高清
@asyncio.coroutine
def function():
...
和
async def function():
...
互換使用。
這兩者之間是否有功能差異?
隨着asyncio
庫我見過,@ asyncio.coroutine VS異步高清
@asyncio.coroutine
def function():
...
和
async def function():
...
互換使用。
這兩者之間是否有功能差異?
是的,使用async def
語法和使用asyncio.coroutine
修飾符的基於生成器的協同程序在原生協程之間存在功能差異。
根據PEP 492,其中介紹了async def
語法:
原住民協程對象不落實
__iter__
和__next__
方法。因此,它們不能迭代或通過 到iter()
,list()
,tuple()
和其他內置程序。他們也 不能用於for..in
循環。使用
__iter__
或__next__
本地協同程序 對象將導致類型錯誤的嘗試。平原發電機不能
yield from
本地協同程序:這樣做 將導致一個TypeError。基於生成器的協同程序(對於ASYNCIO代碼必須與
@asyncio.coroutine
被裝飾)可以yield from
天然協程對象。
inspect.isgenerator()
和inspect.isgeneratorfunction()
爲本地協程對象和本地協程功能回報False
。上述
點1意味着,雖然協程功能使用@asyncio.coroutine
修飾語法可以表現爲傳統功能發生器限定,那些與async def
句法不能限定。
下面是與兩種語法定義的兩個最小的,表面上是等效的協程功能:
import asyncio
@asyncio.coroutine
def decorated(x):
yield from x
async def native(x):
await x
雖然這兩個函數的字節碼是幾乎相同:
>>> import dis
>>> dis.dis(decorated)
5 0 LOAD_FAST 0 (x)
3 GET_YIELD_FROM_ITER
4 LOAD_CONST 0 (None)
7 YIELD_FROM
8 POP_TOP
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
>>> dis.dis(native)
8 0 LOAD_FAST 0 (x)
3 GET_AWAITABLE
4 LOAD_CONST 0 (None)
7 YIELD_FROM
8 POP_TOP
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
...唯一的區別是GET_YIELD_FROM_ITER
VS GET_AWAITABLE
,他們的行爲完全不同,當試圖遍歷的對象他們返回:
>>> list(decorated('foo'))
['f', 'o', 'o']
>>> list(native('foo'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'coroutine' object is not iterable
顯然'foo'
不是awaitable,所以試圖調用native()
與它沒有多大意義,但關鍵是希望明確表示,coroutine
對象返回不迭代,不管其論證如何。
Brett Cannon的async
/await
語法更詳細的研究:How the heck does async/await work in Python 3.5?更深入地涵蓋了這種差異。
async def
是來自Python 3.5的新語法。 您可以在async def
s內使用await
,async with
和async for
。
@coroutine
是async def
功能類似物,但它工作在Python 3.4+和利用yield from
建設,而不是await
。
從實踐的角度來看,如果你的Python是3.5+,就不要使用@coroutine
。
從的Python 3.5coroutines
正式成爲獨特的類型,因此async def
語法,用await
語句一起。
在此之前,的Python 3.4創建協程通過纏繞正則函數成generators
,因此修飾語法,和多個發生器狀yield from
。
將是一件好事知道到底爲什麼在3.5+「從不使用@coroutine」。有沒有真正的理由還是它是一種意見/經驗法則?例如,我在3.4繼承的代碼庫中有一些@coroutine裝飾器,但所有新的開發都在3.5。我應該把這些裝飾器變成'async def'嗎? – hmijail
要暫停協程執行,有必要「屈服」。但是'yield'不允許來自本地協程內部!如此看來,它仍然必要的,即使在Python 3.5 +使用'@ coroutine' – lesnik
號只需使用'等待asyncio.sleep(0)'。 –