编程语言
首页 > 编程语言> > python – 异步函数的可选同步接口

python – 异步函数的可选同步接口

作者:互联网

我正在编写一个库,它使用Tornado Web的tornado.httpclient.AsyncHTTPClient来发出请求,这些请求为我的代码提供了一个异步接口:

async def my_library_function():
    return await ...

如果用户提供了一个kwarg,我想让这个接口可选地串行 – 例如:serial = True.虽然您无法在没有等待的情况下从普通函数中调用使用async关键字定义的函数.这将是理想的 – 虽然目前语言几乎肯定是不可能的:

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

我无法在网上找到任何人提出一个很好的解决方案.我不想重新实现基本相同的代码,而不是一直在等待.

这是可以解决的问题还是需要语言支持?

解决方案(虽然使用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做出回应,并因为这个原因礼貌地将其击落:

Code smell — being able to call the same function both asynchronously
and synchronously is highly surprising. Also it violates the rule of
thumb that the value of an argument shouldn’t affect the return type.

很高兴知道它可能虽然不被认为是一个很棒的界面. 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,asynchronous,synchronous,tornado
来源: https://codeday.me/bug/20190608/1198982.html