当阻塞工作完成时,键盘中断未被捕获

问题描述 投票:0回答:1

要停止以下代码,需要按

Ctrl-C
两次,但是第二个引发的
KeyboardInterrupt
异常不会被
try-catch
方法内的内部
start_consuming
捕获。

import asyncio


async def start_consuming():
    try:
        await asyncio.Future()
    except:
        try:
            await asyncio.Future()
        except:
            pass


async def main():
    await asyncio.gather(start_consuming())


if __name__ == '__main__':
    asyncio.run(main())

为什么?

python exception error-handling python-asyncio
1个回答
0
投票

事实并非如此。这是添加了一些调试打印的程序。

import asyncio

async def start_consuming():
    try:
        await asyncio.Future()
    except BaseException as b:
        print(1, repr(b))

    try:
        await asyncio.Future()
    except BaseException as b:
        print(2, repr(b))

async def main():
    try:
        await asyncio.gather(start_consuming())
    except BaseException as b:
        print(3, repr(b))

if __name__ == '__main__':
    try:
        asyncio.run(main())
    except BaseException as b:
        print (4, repr(b))

输出稍作编辑:

^C 1 CancelledError()

^C 2 CancelledError()

3 CancelledError()

4 KeyboardInterrupt()

我没有完整详细的解释,但很明显,当 ctrl-C 中断到达时,

start_consuming
协程没有执行,因为它还没有准备好。

中断(异常)随后被 asyncio 本身捕获(“捕获”)。在我看来,其他一切都是异步关闭和清理操作。然后,在退出 asyncio 期间,会通过

asyncio.run()
引发 ctrl-C 中断。

我想添加一个关于 asyncio 关闭的注释,“吞掉”取消异常 - 这也是

BaseException
- 是违反规则的。文档:“当取消异步任务时,可以捕获此异常以执行自定义操作。几乎在所有情况下,都必须重新引发异常。”

© www.soinside.com 2019 - 2024. All rights reserved.