编程语言
首页 > 编程语言> > Asyncio异常处理程序:直到事件循环线程停止才被调用

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()

如我们所料,此代码将显示“已调用异常处理程序”.但是,如果我删除了关闭事件循环的行(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()返回一个保存异常的未来对象(它不会到达默认的异常处理程序):

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()或sure_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-asyncio,python
来源: https://codeday.me/bug/20191110/2014823.html