簡體   English   中英

Asyncio異常處理程序:在事件循環線程停止之前不會被調用

[英]Asyncio exception handler: not getting called until event loop thread stopped

我在我的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()在它之前調用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()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)

但是,您應該考慮使用隊列來與您的線程進行通信。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM