2016-09-29 73 views
2

我正在寫使用龍捲風網絡的tornado.httpclient.AsyncHTTPClient使這給我的代碼的async接口請求庫:可選同步接口異步函數

async def my_library_function(): 
    return await ... 

我想使這個接口,如果可選串口用戶提供一個kwarg - 如:serial=True。雖然你不能明確地調用async關鍵字中定義的函數,但不需要使用await。這將是理想的 - 但幾乎可以肯定IMPOSIBLE的語言在此刻:

async def here_we_go(): 
    result = await my_library_function() 
    result = my_library_function(serial=True) 

我沒能在網上找到的任何東西,其中某人想出了一個很好的解決這個。我不想在沒有awaits的情況下重新實現基本相同的代碼。

這是可以解決的問題,還是需要語言支持?


解決方案(雖然使用傑西的,而不是 - 解釋如下)

下面傑西的解決方案几乎是什麼,我會去用。我最終通過使用裝飾器來獲得我最初想要的界面。事情是這樣的:

import asyncio 
from functools import wraps 


def serializable(f): 
    @wraps(f) 
    def wrapper(*args, asynchronous=False, **kwargs): 
     if asynchronous: 
      return f(*args, **kwargs) 
     else: 
      # Get pythons current execution thread and use that 
      loop = asyncio.get_event_loop() 
      return loop.run_until_complete(f(*args, **kwargs)) 
    return wrapper 

這給了你這個接口:

result = await my_library_function(asynchronous=True) 
result = my_library_function(asynchronous=False) 

我的理智檢查這條巨蟒的異步郵寄名單上,我很幸運,有圭多回應,他禮貌地拍下來這個原因:

代碼異味 - 能夠異步調用相同的功能 和同步是非常令人驚訝的。它也違反了 的規則,即參數的值不應該影響返回類型。

很高興知道這是可能的,但如果不被認爲是一個偉大的接口。 Guido基本上提出了Jesse的回答,並將包裝函數作爲庫中的輔助函數使用,而不是將其隱藏在裝飾器中。

+0

也許寫的代碼作爲發電機基於corou然後使用[types.coroutine()](https://www.python.org/dev/peps/pep-0492/#types-coroutine)創建異步等效項? –

回答

3

當你想同步調用這樣的功能,使用run_until_complete

asyncio.get_event_loop().run_until_complete(here_we_go()) 

當然,如果你在你的代碼做到這一點的時候,你應該拿出這個語句的縮寫,或許只是:

def sync(fn, *args, **kwargs): 
    return asyncio.get_event_loop().run_until_complete(fn(*args, **kwargs)) 

然後,你可以這樣做:

result = sync(here_we_go)