【问题标题】:How can I tell which async task didn't complete?我怎么知道哪个异步任务没有完成?
【发布时间】:2019-01-08 04:33:16
【问题描述】:

我正在 python 3.6 中创建和运行一堆异步任务。当我的应用程序退出时,我收到ERROR Task was destroyed but it is pending! 错误,因为我无法清理某些东西。我想调试一下。

Asyncio 很好地告诉我哪个源代码行创建了仍待处理的任务,但这对我没有帮助,因为我的所有任务都是在同一点创建的。我怎么知道哪个任务是延迟的?我可以清楚地命名任务(添加名称属性并在 repr() 中使用它),但是我从 asyncio 得到的错误不会在任务上调用 repr()。 或者,我怎样才能捕捉到“任务被破坏”异常,或者在那里停止 pdb?

【问题讨论】:

  • “任务已销毁,但处于挂起状态”可能表示事件循环已停止,而某些任务甚至没有机会开始运行,更多详细信息 here。要对此进行调试,您可以在停止事件循环的位置(或关闭它或程序退出的位置)迭代Task.all_tasks(),并使用自定义属性将它们区分开来找出未决的循环。
  • 是的,这确实是正在发生的事情;事件循环正在停止,而任务仍在运行。但我不是停止事件循环的人。这发生在我的测试工具中的某个地方。不过,您检查Task.all_tasks() 的想法可能对我有所帮助;我会尝试在几个可能的地方插入它。我希望该错误只会打印实际任务!
  • 现在我注意到您实际上可以调用loop.set_exception_handler 来设置您自己的处理程序。它使用包含任务对象和消息的 dict 调用。您可以打印任务,停止进入pdb等。
  • 啊哈,太好了,@user4815162342!如果你把它变成答案,我会选择它为正确的。

标签: python-3.x async-await python-asyncio


【解决方案1】:

“任务已销毁,但未决”消息可能表示事件循环已停止,而某些任务甚至没有机会开始运行,例如 here 所述。

消息由事件循环打印,因此您可以通过使用set_exception_handler注册自己的处理程序来调试它:

import asyncio

def report(loop, context):
    if 'task' in context:
        task = context['task']
        print(context['message'])
        import pdb; pdb.set_trace()

async def dummy():
    pass

def test():
    loop = asyncio.get_event_loop()
    loop.set_exception_handler(report)
    loop.call_soon(loop.create_task, dummy())
    loop.call_soon(loop.stop)
    loop.run_forever()
    loop.close()

test()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多