【问题标题】:asyncio: loop.run_until_complete(loop.create_task(f)) prints "Task exception was never retrieved" even though it clearly was propagatedasyncio: loop.run_until_complete(loop.create_task(f)) 打印“从未检索到任务异常”,即使它显然已被传播
【发布时间】:2016-03-30 05:58:57
【问题描述】:

由于某种原因,该程序会打印以下警告:

Task exception was never retrieved
future: <Task finished coro=<coro() done, defined at /usr/lib64/python3.4/asyncio/coroutines.py:139> exception=SystemExit(2,)>

即使异常被清楚地检索和传播,因为caught SystemExit!被打印到终端,并且进程状态代码变为2。

Python 2 和 trollius 也会发生同样的事情。

我错过了什么吗?

#!/usr/bin/env python3

import asyncio

@asyncio.coroutine
def comain():
    raise SystemExit(2)

def main():
    loop = asyncio.get_event_loop()
    task = loop.create_task(comain())
    try:
        loop.run_until_complete(task)
    except SystemExit:
        print("caught SystemExit!")
        raise
    finally:
        loop.close()

if __name__ == "__main__":
    main()

【问题讨论】:

  • 有什么理由不使用loop.run_until_complete(comain()),它可以按预期工作吗?
  • 我需要一个任务对象,因为我在 KeyboardInterrupt 处理程序中调用了 task.cancel()(未在此 sn-p 中显示)。
  • 您可以将if not task.cancelled(): task.result() 添加到 finally 块中。虽然我不知道你必须手动调用task.result()task.exception() 是否是预期的行为(我希望run_until_complete() 为你做这件事)。

标签: python python-3.x exception coroutine python-asyncio


【解决方案1】:

SystemExit 似乎是一个特例。例如,如果您提出并捕获Exception,您将不会看到任何错误。 解决这个问题的方法似乎是使用Task.exception()手动检索异常:

import asyncio

@asyncio.coroutine
def comain():
    raise SystemExit(2)

def main():
    loop = asyncio.get_event_loop()
    task = loop.create_task(comain())
    try:
        loop.run_until_complete(task)
    except SystemExit:
        print("caught SystemExit!")
        task.exception()
        raise
    finally:
        loop.close()

if __name__ == "__main__":
    main()

编辑

实际上,所有BaseException 子类都会以这种方式运行。

【讨论】:

    【解决方案2】:

    我认为这是因为SystemExitKeyboardInterrupt 是不同的情况。例如,普通Exception 不会引起同样的问题。

    您可以将 comain 协程链接到另一个协程中,以使用如下所示的异常:

    #!/usr/bin/env python3
    
    import asyncio
    
    @asyncio.coroutine
    def comain():
        raise SystemExit(2)
    
    @asyncio.coroutine
    def another():
        try:
            yield from comain()
        except SystemExit:
            print ("consumed")
    
    def main():
        loop = asyncio.get_event_loop()
        task = loop.create_task(another())
        try:
            loop.run_until_complete(task)
        except SystemExit:
            print("caught SystemExit!")
            raise
        finally:
            loop.close()
    
    if __name__ == "__main__":
        main()
    

    在这里 - 我正在调用 another() 而不是 comain() 并且在 another() 内部我正在处理来自 comain() 的异常。

    【讨论】:

    • 我的意图是让这个异常逃到顶层,这样解释器就会被终止。
    猜你喜欢
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    • 1970-01-01
    • 2022-07-07
    • 2017-04-29
    • 1970-01-01
    相关资源
    最近更新 更多