为什么我只能在异步函数中使用await关键字?

时间:2018-08-26 14:09:15

标签: python python-asyncio

假设我有这样的代码

async def fetch_text() -> str:
    return "text "

async def show_something():
    something = await fetch_text()
    print(something)

哪个好。但是然后我想清除数据,所以我这样做

async def fetch_text() -> str:
    return "text "

def fetch_clean_text(text: str) -> str:
    text = await fetch_text()
    return text.strip(text)

async def show_something():
    something = fetch_clean_text()
    print(something)

(我可以清除show_something()内的文本,但我们假设show_something()可以打印很多东西,并且不知道或不应该知道清理它们的正确方法。)

这当然是SyntaxError: 'await' outside async function。但是,如果此代码可以运行,则在await表达式未放置在协程函数内部的情况下,它在一个上下文中被执行。为什么不允许这种行为?

我看到这种设计的一个专业人士;在我的后一个示例中,您看不到show_something()的身体正在做一些可能导致其暂停的操作。但是,如果我要使fetch_clean_text()成为协程,不仅会使事情复杂化,而且可能还会降低性能。拥有另一个本身不执行任何I / O的协程几乎没有什么意义。有更好的方法吗?

1 个答案:

答案 0 :(得分:2)

  

我看到这种设计的一个专业人士;在我后面的示例中,您看不到   show_something()的身体正在做某事,可能会导致其   暂停。

这正是它采用这种方式设计的原因。编写并发代码可能非常棘手,并且asyncio作者认为始终显式标记代码中的挂起位置至关重要。

This article对其进行了详细说明(您可以从“ Get To the Point Already”段落开始)。

  

但是,如果我要将fetch_clean_text()用作协程,不仅   它会使事情复杂化,但可能还会降低性能。

在处理I / O时,几乎只需要协程。与使用协程相比,I / O总是比开销花费更多的时间。因此,我想可以说-不,与您已经处理过的I / O相比,使用协程不会浪费大量执行时间。

  

有更好的方法吗?

我只能建议的方法是:将处理I / O(异步部分)的逻辑与其余代码(同步部分)分开。

from typing import Awaitable

def clean_text(text: str) -> str:
    return text.strip(text)

async def fetch_text() -> Awaitable[str]:
    return "text "

async def fetch_clean_text(text: str) -> Awaitable[str]:
    text = await fetch_text()
    return clean_text(text)

async def show_something():
    something = await fetch_clean_text()
    print(something)