简体   繁体   English

使用循环 run_in_executor 时如何使用 CTRL-C 优雅地结束异步程序

[英]How to gracefully end asyncio program with CTRL-C when using loop run_in_executor

The following code requires 3 presses of CTRL-C to end, how can I make it end with one only?下面的代码需要按 3 次 CTRL-C 才能结束,我怎样才能让它只按一次结束呢? (So it works nicely in Docker) (因此它在 Docker 中运行良好)

import asyncio
import time


def sleep_blocking():
    print("Sleep blocking")
    time.sleep(1000)


async def main():
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, sleep_blocking)


try:
    asyncio.run(main())
except KeyboardInterrupt:
    print("Nicely shutting down ...")

I've read many asyncio related questions and answers but can't figure this one out yet.我已经阅读了许多与 asyncio 相关的问题和答案,但还无法弄清楚这一点。 The 1st CTRL-C does nothing, the 2nd prints "Nicely shutting down..." and then hangs.第一个 CTRL-C 什么都不做,第二个打印“Nicely shutting down...”然后挂起。 The 3rd CTRL-C prints an ugly error.第三次 CTRL-C 打印出一个丑陋的错误。

I'm on Python 3.9.10 and Linux.我在 Python 3.9.10 和 Linux 上。

(edit: updated code per comment @mkrieger1) (编辑:根据@mkrieger1 的评论更新代码)

The way to exit immediately and unconditionally from a Python program is by calling os._exit().立即无条件退出 Python 程序的方法是调用 os._exit()。 If your background threads are in the middle of doing something important this may not be wise.如果你的后台线程正在做一些重要的事情,这可能是不明智的。 However the following program does what you asked (python 3.10, Windows10):但是,以下程序会按照您的要求进行操作(python 3.10,Windows10):

import asyncio
import time
import os


def sleep_blocking():
    print("Sleep blocking")
    time.sleep(1000)


async def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(loop.run_in_executor(None, sleep_blocking))


try:
    asyncio.run(main())
except KeyboardInterrupt:
    print("Nicely shutting down ...")
    os._exit(42)

From here we know that it's effectively impossible to kill a task running in a thread executor.这里我们知道实际上不可能终止在线程执行器中运行的任务。 If I replace the default thread executor with a ProcessPoolExecutor , I get the behavior you're looking for.如果我用ProcessPoolExecutor替换默认线程执行器,我会得到您正在寻找的行为。 Here's the code:这是代码:

import concurrent.futures
import asyncio
import time


def sleep_blocking():
    print("Sleep blocking")
    time.sleep(1000)


async def main():
    loop = asyncio.get_event_loop()
    x = concurrent.futures.ProcessPoolExecutor()
    await loop.run_in_executor(x, sleep_blocking)


try:
    asyncio.run(main())
except KeyboardInterrupt:
    print("Nicely shutting down ...")

And the result is:结果是:

$ python asynctest.py
Sleep blocking
^CNicely shutting down ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 Ctrl-C 优雅地终止 asyncio 脚本? - How to gracefully terminate an asyncio script with Ctrl-C? 在asyncio中使用run_in_executor时,事件循环是否在主线程中执行? - When using run_in_executor in asyncio, is the event loop executed in the main thread? 在没有 asyncio.get_event_loop() 的 run_in_executor 的异步方法中使用线程池 - Using Threadpool in an Async method without run_in_executor of asyncio.get_event_loop() 使用 run_in_executor 和 asyncio 时的超时处理 - Timeout handling while using run_in_executor and asyncio 为什么asyncio的run_in_executor在发出HTTP请求时提供的并行化程度如此之低? - Why asyncio's run_in_executor gives so little parallelization when making HTTP requests? “GIL”如何影响 Python asyncio `run_in_executor` 与 i/o 绑定任务? - How "GIL" affects Python asyncio `run_in_executor` with i/o bound tasks? python asyncio取消run_in_executor阻塞主线程 - python asyncio cancel run_in_executor blocks mainthread 如何使用run_in_executor对吗? - How to use run_in_executor right? 在python中按下CTRL + C时如何优雅地终止循环 - How to terminate loop gracefully when CTRL+C was pressed in python 用户调用Ctrl-C时保存程序状态 - Saving program state when user invokes Ctrl-C
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM