1

以下代码工作正常:

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')

装饰使它工作b@asyncio.coroutine

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

4

1 回答 1

4

您的代码会产生以下错误:

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

正如错误消息中明确指出的那样,使用 asyncio 时,您应该使用@coroutineasync def标记您的协程。在async defs 中,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')

您的第一个示例被认为是“错误的”,但它正在“正确”执行,因为当前为生成器返回 True 的run_until_complete调用iscoroutine(任何def带有yield/ yield from),但这是一个实现细节,可能会在未来版本的 python 中发生变化。使用@couroutineon def a()(而不是async def a()),甚至只是添加yield from asyncio.sleep(1)到常规def a() 中,也会使您的第二个示例也运行。当前,当使用未在 asyncio 中标记为协程的生成器时,python 可能是“仁慈的”,但在使用async defs.

于 2017-01-17T08:36:39.760 回答