python - 异步异常处理程序 : not getting called until event loop thread stopped

标签 python python-asyncio

我正在我的 asyncio 事件循环上设置异常处理程序。但是,在事件循环线程停止之前,它似乎不会被调用。例如,考虑这段代码:

def exception_handler(loop, context):
    print('Exception handler called')

loop = asyncio.get_event_loop()

loop.set_exception_handler(exception_handler)

thread = Thread(target=loop.run_forever)
thread.start()

async def run():
    raise RuntimeError()

asyncio.run_coroutine_threadsafe(run(), loop)

loop.call_soon_threadsafe(loop.stop, loop)

thread.join()

如我们所料,这段代码打印出“Exception handler called”。但是,如果我删除关闭事件循环的行 (loop.call_soon_threadsafe(loop.stop, loop)),它将不再打印任何内容。

我有几个问题:

  • 我是不是做错了什么?

  • 有谁知道这是否是 asyncio 异常处理程序的预期行为?我找不到任何可以证明这一点的东西,这对我来说似乎有点奇怪。

我非常希望有一个长时间运行的事件循环来记录其协程中发生的错误,因此当前的行为对我来说似乎有问题。

最佳答案

上面的代码有几个问题:

  • stop()不需要参数
  • 程序在协程执行之前结束(stop() 在它之前被调用)。

这是固定代码(没有异常和异常处理程序):

import asyncio
from threading import Thread


async def coro():
    print("in coro")
    return 42


loop = asyncio.get_event_loop()
thread = Thread(target=loop.run_forever)
thread.start()

fut = asyncio.run_coroutine_threadsafe(coro(), loop)

print(fut.result())

loop.call_soon_threadsafe(loop.stop)

thread.join()

call_soon_threadsafe() 返回一个包含异常的 future 对象(它不会到达默认的异常处理程序):

import asyncio
from pprint import pprint
from threading import Thread


def exception_handler(loop, context):
    print('Exception handler called')
    pprint(context)


loop = asyncio.get_event_loop()

loop.set_exception_handler(exception_handler)

thread = Thread(target=loop.run_forever)
thread.start()


async def coro():
    print("coro")
    raise RuntimeError("BOOM!")


fut = asyncio.run_coroutine_threadsafe(coro(), loop)
try:
    print("success:", fut.result())
except:
    print("exception:", fut.exception())

loop.call_soon_threadsafe(loop.stop)

thread.join()

但是,使用 create_task()ensure_future() 调用的协程将调用 exception_handler:

async def coro2():
    print("coro2")
    raise RuntimeError("BOOM2!")


async def coro():
    loop.create_task(coro2())
    print("coro")
    raise RuntimeError("BOOM!")

您可以使用它来创建一个小的包装器:

async def boom(x):
    print("boom", x)
    raise RuntimeError("BOOM!")


async def call_later(coro, *args, **kwargs):
    loop.create_task(coro(*args, **kwargs))
    return "ok"


fut = asyncio.run_coroutine_threadsafe(call_later(boom, 7), loop)

但是,您可能应该考虑使用 Queue改为与您的线程通信。

关于python - 异步异常处理程序 : not getting called until event loop thread stopped,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47413359/

相关文章:

python - 在 DJANGO 模板中总结数据库中的值

python - 在 fixture 中包含代码后,带有异步的 pytest 中的 AttributeError

Python - 如何取消由 python-trio 中的托儿所产生的特定任务

python - 如何监控 Python 事件循环的繁忙程度?

python - 使用变形的相关/级联输入

Python - 使用 Pytesseract 读取图像中的数字

python - 如果答案无效,程序将不会打印并再次循环

python - 使用 Python 如何合并两列并仅在另一列中的数据存在时覆盖一列中的数据?

python-3.x - 如何使用 asyncio 和 redis 创建全局连接

python - 异步IO。如何异步调用1000个方法并在准备好后立即获取异步结果