【问题标题】:Why does this asyncio.Task never finish cancelling?为什么这个 asyncio.Task 永远不会完成取消?
【发布时间】:2015-08-08 02:00:51
【问题描述】:

如果我在 python3 解释器上运行它:

import asyncio

@asyncio.coroutine
def wait(n):
    asyncio.sleep(n)

loop = asyncio.get_event_loop()
fut = asyncio.async(wait(10))
fut.add_done_callback(lambda x: print('Done'))

asyncio.Task.all_tasks()

我得到以下结果:

{<Task pending coro=<coro() running at /usr/local/Cellar/python3/3.4.3/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/coroutines.py:139> cb=[<lambda>() at <ipython-input-5-c72c2da2ffa4>:1]>}

现在,如果我运行 fut.cancel(),我会返回 True。但是输入 fut 会返回任务的表示,说明它正在取消

<Task cancelling coro=<coro() running at /usr/local/Cellar/python3/3.4.3/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/coroutines.py:139> cb=[<lambda>() at <ipython-input-5-c72c2da2ffa4>:1]>

而且任务实际上永远不会取消(fut.cancelled() 永远不会返回 True

为什么不取消?

【问题讨论】:

  • 你可能实际上想要yield from asyncio.sleep(n)wait 中。否则,wait 将退出而不实际休眠 n 秒。

标签: python python-3.x concurrency python-asyncio


【解决方案1】:

调用task.cancel()只会安排任务在事件循环的下一次运行时被取消;它不会立即取消任务,甚至不会保证在事件循环运行下一次迭代时该任务实际上会被取消。这都是in the documentation描述的:

取消()

请求此任务自行取消。

这会安排将CancelledError 扔进包装中 协程通过事件循环的下一个循环。那么协程 有机会使用 尝试/除了/最后。

Future.cancel() 不同,这并不能保证任务会 取消:异常可能被捕获并采取行动,延迟 取消任务或完全阻止取消。这 任务也可能返回一个值或引发不同的异常。

调用此方法后,cancelled() 将不会立即返回 True(除非任务已经取消)。任务将被标记为 当包装的协程以 CancelledError 终止时取消 异常(即使 cancel() 未被调用)。

在您的情况下,您实际上从未启动事件循环,因此该任务永远不会被取消。您需要致电 loop.run_until_complete(fut)(或 loop.run_forever(),尽管对于这种特殊情况来说这并不是最佳选择)才能真正取消任务。

此外,不管怎样,使用实际脚本而不是解释器来测试 asyncio 代码通常更容易,因为不得不不断重写协程和启动/停止事件循环往往会变得乏味。

【讨论】:

  • 我认为完美的答案是将我自己的答案与这个答案结合起来。如果你把它们和你的结合起来,我会接受的。
【解决方案2】:

使用 asyncio 在解释器中进行测试是很棘手的,因为 python 需要保持事件循环不断地轮询它的任务。

所以测试 asyncio 的一些建议是:

  1. 编写和运行脚本而不是使用交互式解释器
  2. 在脚本末尾添加loop.run_forever(),以便执行所有任务。
  3. 另一种方法是为您要运行的每个任务运行loop.run_until_complete(coro())
  4. asyncio.sleep(n) 前面加上yield from,这样它就可以实际运行了。当前代码返回一个生成器并且什么都不做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 2015-01-18
    • 2019-08-31
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多