2016-11-13 145 views

回答

29

是的,使用async def語法和使用asyncio.coroutine修飾符的基於生成器的協同程序在原生協程之間存在功能差異。

根據PEP 492,其中介紹了async def語法:

  1. 原住民協程對象不落實__iter____next__方法。因此,它們不能迭代或通過 到iter(),list(),tuple()和其他內置程序。他們也 不能用於for..in循環。

    使用__iter____next__本地協同程序 對象將導致類型錯誤的嘗試。

  2. 平原發電機不能yield from本地協同程序:這樣做 將導致一個TypeError。

  3. 基於生成器的協同程序(對於ASYNCIO代碼必須與 @asyncio.coroutine被裝飾)可以yield from天然協程對象

  4. 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?更深入地涵蓋了這種差異。

10

async def是來自Python 3.5的新語法。 您可以在async def s內使用await,async withasync for

@coroutineasync def功能類似物,但它工作在Python 3.4+和利用yield from建設,而不是await

從實踐的角度來看,如果你的Python是3.5+,就不要使用@coroutine

+0

將是一件好事知道到底爲什麼在3.5+「從不使用@coroutine」。有沒有真正的理由還是它是一種意見/經驗法則?例如,我在3.4繼承的代碼庫中有一些@coroutine裝飾器,但所有新的開發都在3.5。我應該把這些裝飾器變成'async def'嗎? – hmijail

+0

要暫停協程執行,有必要「屈服」。但是'yield'不允許來自本地協程內部!如此看來,它仍然必要的,即使在Python 3.5 +使用'@ coroutine' – lesnik

+0

號只需使用'等待asyncio.sleep(0)'。 –

3

的Python 3.5coroutines正式成爲獨特的類型,因此async def語法,用await語句一起。

在此之前,的Python 3.4創建協程通過纏繞正則函數成generators,因此修飾語法,和多個發生器狀yield from