簡體   English   中英

如何使用 Ctrl-C 優雅地終止 asyncio 腳本?

[英]How to gracefully terminate an asyncio script with Ctrl-C?

我已經閱讀了我能找到的每一篇關於如何優雅地處理帶有 Ctrl-C 終止的 asyncio 事件循環的腳本的帖子,而且我無法在不打印一個或多個回溯的情況下讓它們中的任何一個工作,因為我這樣做。 答案幾乎無處不在,我還沒有能夠將它們中的任何一個實現到這個小腳本中:

import asyncio
import datetime
import functools
import signal


async def display_date(loop):
    end_time = loop.time() + 5.0
    while True:
        print(datetime.datetime.now())
        if (loop.time() + 1.0) >= end_time:
            break
        await asyncio.sleep(1)


def stopper(signame, loop):
    print("Got %s, stopping..." % signame)
    loop.stop()


loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame), functools.partial(stopper, signame, loop))

loop.run_until_complete(display_date(loop))
loop.close()

我想要發生的是讓腳本退出而不打印 Ctrl-C (或通過kill發送的 SIGTERM/SIGINT 之后的任何回溯)。 此代碼打印RuntimeError: Event loop stopped before Future completed. 在我根據以前的答案嘗試過的許多其他形式中,我收到了大量其他類型的異常類和錯誤消息,但不知道如何修復它們。 上面的代碼現在是最少的,但是我之前所做的一些嘗試卻完全沒有,而且沒有一個是正確的。

如果您能夠修改腳本以使其正常終止,那么將不勝感激地解釋為什么您的方法是正確的

使用信號處理程序:

import asyncio
from signal import SIGINT, SIGTERM

async def main_coro():
    try:
        await awaitable()
    except asyncio.CancelledError:
        do_cleanup()

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    main_task = asyncio.ensure_future(main_coro())
    for signal in [SIGINT, SIGTERM]:
        loop.add_signal_handler(signal, main_task.cancel)
    try:
        loop.run_until_complete(main_task)
    finally:
        loop.close()

在運行時停止事件循環永遠不會有效。

在這里,您需要抓住 Ctrl-C,向 Python 表明您希望自己處理它,而不是顯示默認的堆棧跟蹤。 這可以通過經典的 try/except 來完成:

coro = display_date(loop)
try:
    loop.run_until_complete(coro)
except KeyboardInterrupt:
    print("Received exit, exiting")

而且,對於您的用例,就是這樣! 對於更真實的程序,您可能需要清理一些資源。 另請參閱asyncio 協程的正常關閉

暫無
暫無

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

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