异步设计/实现

时间:2019-05-08 09:57:55

标签: python async-await python-asyncio

我最近开始用Python实现一些async代码,并且对设计和实现有些疑问。 例如,如果我必须做一些事情,让我将同步代码称为非async函数,而我只有一个async函数,返回协程是否被视为不良习惯或不良设计? 让我用一些代码更好地解释一下:

def my_async_function():
    #some sync code
    return async_code()

代替:

async def my_async_function():
    #some sync code
    return await async_code()

您认为第一个版本可能会隐藏一些问题吗?
或者总的来说,每条建议都会受到赞赏,因为我是这种代码风格的新手。
附注:对不起,我的英语,我希望这是可以理解的。

1 个答案:

答案 0 :(得分:0)

两个变体都是完全正确的,但是如果有疑问,请选择第二个变体。这将使呼叫者清楚地知道他们正在处理协程,并且仅与协程进行处理。

两者之间存在技术上的区别,但是只有在呼叫者不立即等待时,它才会变得明显。考虑以下代码:

aw = my_async_function()
# ... do something here ...
result = await aw

在您的第一个示例中,“某些同步代码”将在您调用该函数后立即运行,因此,如果有副作用,则可以在“在此处执行操作”中看到它们。在第二个示例中,仅调用my_async_function()是完全没有副作用的,它仅创建协程对象。在该变体中,“某些同步代码”仅在await aw上执行,即在“在这里做某事”已经运行之后。

将协程定义为async def可确保调用方在实际等待协程结果之前不会运行任何同步代码,这可能是重要的保证。即使该函数不是async且仅返回一个等待的值,也应建议其行为好像坚持这一保证,至少在调用者可以观察到的范围内。< / p>

一个不遵循该原理的著名示例是run_in_executor,它立即将可调用对象提交到线程池。因此,run_in_executor永远无法成为真正的协程,因为这样会破坏调用它的代码,而不会打扰await(或由于任何原因而等待的代码)。