我正在编写一个使用Tornado Web的tornado.httpclient.AsyncHTTPClient
发出请求的库,该库为我的代码提供了async
接口(interface):
async def my_library_function():
return await ...
如果用户提供了kwarg-类似
serial=True
,我希望将此接口(interface)可选地设置为串行。尽管您显然不能从没有async
的普通函数中调用用await
关键字定义的函数。这将是理想的-尽管目前在该语言中几乎是不可能的:async def here_we_go():
result = await my_library_function()
result = my_library_function(serial=True)
我无法在网上找到任何东西,有人为此提出了一个不错的解决方案。我不需要重新实现基本相同的代码,而无需将
awaits
散布在整个过程中。这是可以解决的问题,还是需要语言的支持?
解决方案(尽管使用Jesse的解决方案-下文说明)
Jesse下面的解决方案几乎是我要使用的解决方案。我最终还是通过使用装饰器获得了我最初想要的界面。像这样的东西:
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)
我理智地在python的异步邮件列表中检查了这一点,我很幸运地让Guido做出了响应,因此他有礼貌地拒绝了它:
很高兴知道,即使没有被认为是一个很好的界面,它也是有可能的。 Guido本质上提出了Jesse的答案,并在库中引入了包装功能作为辅助工具,而不是将其隐藏在装饰器中。
最佳答案
当您要同步调用此类函数时,请使用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)
关于python - 异步功能的可选同步接口(interface),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39778901/