Python中asyncio的await回调需要满足什么条件?

1 import asyncio 2 3 def addone(x,y): 4 x = x+1 5 y = y+1 6 print("x={}".format(x)) 7
8 async def compute(x, y): 9 print('Compute {} + {} ...'.format(x, y)) 10 #await asyncio.sleep(1.0) 11 await addone(x,y) 12 return x + y 13
14 async def print_sum(x, y): 15 result = await compute(x, y) 16 print('{} + {} = {}'.format(x, y, result)) 17
18 loop = asyncio.get_event_loop() 19 loop.run_until_complete(print_sum(1, 2)) 20 loop.close()

上面这样的代码报出来结果是这样 await addone(x,y) TypeError: object int can't be used in 'await' expression

但是如果改成这样 1 import asyncio 2 3 def addone(x,y): 4 x = x+1 5 y = y+1 6
7
8 async def compute(x, y): 9 print('Compute {} + {} ...'.format(x, y)) 10 await asyncio.sleep(1.0) 11 #await addone(x,y) 12 return x + y 13
14 async def print_sum(x, y): 15 result = await compute(x, y) 16 print('{} + {} = {}'.format(x, y, result)) 17
18 loop = asyncio.get_event_loop() 19 loop.run_until_complete(print_sum(1, 2)) 20 loop.close()

第二种就不会报错,那么 await 后面只能调用异步的函数吗?求大神解答


Python中asyncio的await回调需要满足什么条件?

12 回复

是的


在Python的asyncio里,await后面跟的得是一个可等待对象(Awaitable)。具体来说,主要分三类:

  1. 协程对象(Coroutine):直接async def定义的函数调用后返回的就是这个。这是最常用的。
  2. asyncio.Future对象:这是asyncio内部用于表示异步操作结果的低级对象,通常你不用直接创建它。
  3. 定义了__await__()方法的对象:这个对象可以通过__await__()方法返回一个迭代器。

最核心、最常用的就是第一点:await后面必须是一个协程对象。

错误示例:

import asyncio

async def my_task():
    print("Task done")

async def main():
    # 错误:my_task() 返回一个协程对象,但前面没有 await
    # 这行代码不会执行 my_task 里的打印
    my_task()
    # 正确做法是:
    # await my_task()

asyncio.run(main())

上面的my_task()调用只是创建了一个协程对象,并没有真正执行它。await的作用就是“挂起”当前协程,去驱动my_task()这个协程对象运行,直到它完成。

正确示例:

import asyncio

async def fetch_data():
    await asyncio.sleep(1) # asyncio.sleep() 本身也返回一个可等待对象
    return "Data"

async def main():
    # 正确:await 一个协程对象
    result = await fetch_data()
    print(result)

asyncio.run(main())

简单总结:await后面必须跟一个能“等”的东西,通常就是你用async def定义的函数调一下。

帖子代码格式出了问题,我尝试重新贴一下
1 import asyncio
2
3 def addone(x,y):
4 x = x+1
5 y = y+1
6 print(“x={}”.format(x))
7
8 async def compute(x, y):
9 print(‘Compute {} + {} …’.format(x, y))
10 #await asyncio.sleep(1.0)
11 await addone(x,y)
12 return x + y
13
14 async def print_sum(x, y):
15 result = await compute(x, y)
16 print(’{} + {} = {}’.format(x, y, result))
17
18 loop = asyncio.get_event_loop()
19 loop.run_until_complete(print_sum(1, 2))
20 loop.close()

第一段的代码

报错如下:await addone(x,y) TypeError: object int can’t be used in ‘await’ expression

1 import asyncio
2
3 def addone(x,y):
4 x = x+1
5 y = y+1
6 print(“x={}”.format(x))
7
8 async def compute(x, y):
9 print(‘Compute {} + {} …’.format(x, y))
10 await asyncio.sleep(1.0)
11 #await addone(x,y)
12 return x + y
13
14 async def print_sum(x, y):
15 result = await compute(x, y)
16 print(’{} + {} = {}’.format(x, y, result))
17
18 loop = asyncio.get_event_loop()
19 loop.run_until_complete(print_sum(1, 2))
20 loop.close()

这样就不会报错,那么我只能调用异步的函数吗?如果是,那如何知道哪些内置的函数支持异步?

去掉 11 行的 await

其实就是想问 await 后面能接什么函数而已,如果打掉 11 行的 await,就相当于让渡之后拿到控制权的函数线性执行

await 必须是 async 的方法吧,3.5 之前是通过 decorator 的方式实现的,你读读当时的文档,应该有介绍原理的

跟 coroutine object

你写的几个函数就是应该让他们一直执行啊,IO 操作的时候你才应该用 await 把执行权给别的位置。await 后面应该接一个 awaitable 的东西。

所以是 await 函数接的是 IO 操作对应的函数?不是很懂

“第二种就不会报错,那么 await 后面只能调用异步的函数吗?求大神解答”

代码排版看得头痛,直接跳过了。如果只看标题的话,一个用于 await 语句的对象必须是 awaitable 的,即实现了__await__方法,对应的 abc 是 collections.abc.Awaitable,可以用isinstance(gencoro, Awaitable)进行判断。

此外,基于生成器的 coroutine 对象(用 types.coroutine 和 asyncio.coroutine 修饰器修饰),虽然没有实现__await__方法,但是也被认为是 awaitable 的,可以被用于 await 语句。但是这种对象如果用上面的 isinstance 判断会返回 False。可以使用inspect.isawaitable()判断。

回到顶部