无法通过简单地返回原生异步协程来链接它们
Not possible to chain native asyncio coroutines by simply returning them
我一直在使用 py3.4 的基于生成器的协程,并且在几个地方我通过简单地调用一个协程 return inner_coroutine()
将它们链接起来(如下例所示)。但是,我现在正在将它们转换为使用 py3.5 的本机协程,我发现它不再有效,因为内部协程没有达到 运行(请参阅 运行ning 示例的输出以下)。为了使本机内部协程 运行 我需要使用 return await inner_coroutine()
而不是原来的 return inner_coroutine()
。
我希望本机协程的链接与基于生成器的协程的工作方式相同,并且找不到任何其他说明的文档。我是不是遗漏了什么或者这是原生协程的实际限制?
import asyncio
@asyncio.coroutine
def coro():
print("Inside coro")
@asyncio.coroutine
def outer_coro():
print("Inside outer_coro")
return coro()
async def native_coro():
print("Inside native_coro")
async def native_outer_coro():
print("Inside native_outer_coro")
# return await native_coro() # this works!
return native_coro()
loop = asyncio.get_event_loop()
loop.run_until_complete(outer_coro())
loop.run_until_complete(native_outer_coro())
以及 运行 那个例子的输出:
Inside outer_coro
Inside coro
Inside native_outer_coro
foo.py:26: RuntimeWarning: coroutine 'native_coro' was never awaited
loop.run_until_complete(native_outer_coro())
您的旧版本逻辑错误,仅由于基于生成器的实现不完善才起作用。新语法允许关闭此功能并使 asyncio 更加一致。
协同程序的想法是这样工作的:
c = coro_func() # create coroutine object
coro_res = await c # await this object to get result
在这个例子中...
@asyncio.coroutine
def outer():
return inner()
...等待 outer()
应该 return inner()
协程对象不是此对象的结果 。但由于实施不完善,它等待 inner()
(就像写了 yield from inner()
)。
在新语法中,asyncio 完全按照它应该的方式工作:return它是协程对象而不是它的结果。由于从未等待此协程对象(通常意味着错误),您会收到此警告。
您可以像这样更改代码以清楚地看到它:
loop = asyncio.get_event_loop()
print('old res:', loop.run_until_complete(outer_coro()))
print('new res:', loop.run_until_complete(native_outer_coro()))
这与另一个答案的内容相同,但以我认为作为对问题的回答更容易理解的方式表述。
python判断某事物是生成器还是普通函数的方式是它是否包含yield
语句。
这与 @asyncio.coroutine
产生了歧义。
您的协程是立即执行还是等到调用方对生成的生成器对象调用 next
取决于您的代码是否恰好包含 yield statement
。
本机协程在设计上是明确的生成器,即使它们不碰巧包含任何 await 语句。
这提供了可预测的行为,但不允许您使用的链接形式。
你可以像你指出的那样
return await inner_coroutine()
但是请注意,在等待语法中,在事件循环中执行外部协程时会调用内部协程。但是,使用基于生成器的方法且没有 yield,内部协程是在实际将协程提交给事件循环时构建的。
在大多数情况下,这种差异无关紧要。
我一直在使用 py3.4 的基于生成器的协程,并且在几个地方我通过简单地调用一个协程 return inner_coroutine()
将它们链接起来(如下例所示)。但是,我现在正在将它们转换为使用 py3.5 的本机协程,我发现它不再有效,因为内部协程没有达到 运行(请参阅 运行ning 示例的输出以下)。为了使本机内部协程 运行 我需要使用 return await inner_coroutine()
而不是原来的 return inner_coroutine()
。
我希望本机协程的链接与基于生成器的协程的工作方式相同,并且找不到任何其他说明的文档。我是不是遗漏了什么或者这是原生协程的实际限制?
import asyncio
@asyncio.coroutine
def coro():
print("Inside coro")
@asyncio.coroutine
def outer_coro():
print("Inside outer_coro")
return coro()
async def native_coro():
print("Inside native_coro")
async def native_outer_coro():
print("Inside native_outer_coro")
# return await native_coro() # this works!
return native_coro()
loop = asyncio.get_event_loop()
loop.run_until_complete(outer_coro())
loop.run_until_complete(native_outer_coro())
以及 运行 那个例子的输出:
Inside outer_coro
Inside coro
Inside native_outer_coro
foo.py:26: RuntimeWarning: coroutine 'native_coro' was never awaited
loop.run_until_complete(native_outer_coro())
您的旧版本逻辑错误,仅由于基于生成器的实现不完善才起作用。新语法允许关闭此功能并使 asyncio 更加一致。
协同程序的想法是这样工作的:
c = coro_func() # create coroutine object
coro_res = await c # await this object to get result
在这个例子中...
@asyncio.coroutine
def outer():
return inner()
...等待 outer()
应该 return inner()
协程对象不是此对象的结果 。但由于实施不完善,它等待 inner()
(就像写了 yield from inner()
)。
在新语法中,asyncio 完全按照它应该的方式工作:return它是协程对象而不是它的结果。由于从未等待此协程对象(通常意味着错误),您会收到此警告。
您可以像这样更改代码以清楚地看到它:
loop = asyncio.get_event_loop()
print('old res:', loop.run_until_complete(outer_coro()))
print('new res:', loop.run_until_complete(native_outer_coro()))
这与另一个答案的内容相同,但以我认为作为对问题的回答更容易理解的方式表述。
python判断某事物是生成器还是普通函数的方式是它是否包含yield
语句。
这与 @asyncio.coroutine
产生了歧义。
您的协程是立即执行还是等到调用方对生成的生成器对象调用 next
取决于您的代码是否恰好包含 yield statement
。
本机协程在设计上是明确的生成器,即使它们不碰巧包含任何 await 语句。
这提供了可预测的行为,但不允许您使用的链接形式。
你可以像你指出的那样
return await inner_coroutine()
但是请注意,在等待语法中,在事件循环中执行外部协程时会调用内部协程。但是,使用基于生成器的方法且没有 yield,内部协程是在实际将协程提交给事件循环时构建的。 在大多数情况下,这种差异无关紧要。