yield from asyncio.sleep 有效,但 yield from async def 失败

yield from asyncio.sleep works, but yield from async def fails

以下代码工作正常:

import asyncio
loop = asyncio.get_event_loop()
async def a ():
    print('hello')
def b ():
    yield from asyncio.sleep(1)
loop.run_until_complete(b())
loop.close()
print('done')

但是,以下失败了:

import asyncio
loop = asyncio.get_event_loop()
async def a ():
    print('hello')
def b ():
    yield from a() # <=========== only 1 tiny change
loop.run_until_complete(b())
loop.close()
print('done')

@asyncio.coroutine 装饰 b 使其工作。

但是,问题是为什么第一段代码在没有 @asyncio.coroutine 装饰器的情况下也能正常工作?文档清楚地说 asyncio.sleep 是协程,a 也是,那么为什么代码在一种情况下失败而在另一种情况下工作正常?

您的代码产生以下错误:

...
        yield from a()  # <=========== only 1 tiny change
TypeError: cannot 'yield from' a coroutine object in a non-coroutine generator

正如错误消息中明确指出的那样,在使用 asyncio 时,您应该使用 @coroutineasync def 来标记您的协程。在 async def 中,应该使用 await 而不是 yield from:

import asyncio


async def a():
    print('hello')


async def b():
    await a()


loop = asyncio.get_event_loop()
loop.run_until_complete(b())
loop.close()
print('done')

或者,对于 python 3.4:

import asyncio

@asyncio.coroutine
def a():
    print('hello')


@asyncio.coroutine
def b():
    yield from a()


loop = asyncio.get_event_loop()
loop.run_until_complete(b())
loop.close()

print('done')

您的第一个示例被认为是 "buggy",但它正在执行 "properly" 因为 run_until_complete 调用 iscoroutine 目前 returns 对于生成器(任何 defyield/yield from),但这是一个实现细节,可能会在 python 的未来版本中更改。在 def a() 上使用 @couroutine(而不是 async def a()),或者甚至只是将 yield from asyncio.sleep(1) 添加到常规 def a() 将使您的第二个示例 运行 成为出色地。目前 python 在使用 asyncio 中未标记为协程的生成器时可能是 "merciful",但在使用 async defs 时则不是。