当前位置: 首页 > 面试题库 >

捕获Ctrl + C / SIGINT并在python中优雅退出多进程

穆飞星
2023-03-14
问题内容

如何在多进程python程序中捕获Ctrl+ C,并正常退出所有进程,我需要在Unix和Windows上均可使用的解决方案。我尝试了以下方法:

import multiprocessing
import time
import signal
import sys

jobs = []

def worker():
    signal.signal(signal.SIGINT, signal_handler)
    while(True):
        time.sleep(1.1234)
        print "Working..."

def signal_handler(signal, frame):
    print 'You pressed Ctrl+C!'
    # for p in jobs:
    #     p.terminate()
    sys.exit(0)

if __name__ == "__main__":
    for i in range(50):
        p = multiprocessing.Process(target=worker)
        jobs.append(p)
        p.start()

这是可行的,但我认为这不是正确的解决方案。


问题答案:

正确的方法来处理Ctrl+C/SIGINTmultiprocessing.Pool是:

  1. SIGINTPool创建流程之前,请忽略该流程。这样创建的子进程继承了SIGINT处理程序。
  2. 创建SIGINTa之后,在父进程中还原原始处理程序Pool
  3. 使用map_asyncapply_async代替阻塞mapapply
  4. 等待结果超时,因为默认阻塞将等待忽略所有信号。这是Python错误https://bugs.python.org/issue8296。

把它放在一起:

#!/bin/env python
from __future__ import print_function

import multiprocessing
import os
import signal
import time

def run_worker(delay):
    print("In a worker process", os.getpid())
    time.sleep(delay)

def main():
    print("Initializng 2 workers")
    original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
    pool = multiprocessing.Pool(2)
    signal.signal(signal.SIGINT, original_sigint_handler)
    try:
        print("Starting 2 jobs of 5 seconds each")
        res = pool.map_async(run_worker, [5, 5])
        print("Waiting for results")
        res.get(60) # Without the timeout this blocking call ignores all signals.
    except KeyboardInterrupt:
        print("Caught KeyboardInterrupt, terminating workers")
        pool.terminate()
    else:
        print("Normal termination")
        pool.close()
    pool.join()

if __name__ == "__main__":
    main()

正如@YakovShklarov指出的那样,在父进程中忽略信号和忽略信号之间存在时间窗口,在此期间信号可能会丢失。pthread_sigmask在父进程中使用临时阻止信号的传递可以防止信号丢失,但是在Python-2中不可用。



 类似资料:
  • Ctrl-C/SIGTERM/SIGINT似乎被tkinter忽略。通常情况下,它可以通过回调再次捕获。这似乎不起作用,所以我想我应该在另一个线程中运行tkinter,因为它的main循环()是一个无限循环和块。实际上,我也想这样做,以便在一个单独的线程中阅读stdin。即使在此之后,Ctrl-C仍然不会处理,直到我关闭窗口。这是我的MWE: 结果: 运行应用程序 终端中的Ctrl-C(什么都没发

  • 问题内容: 我正在研究启动多个进程和数据库连接的python脚本。我不时地想用信号杀死脚本,我想进行一些清理。 在Perl中,我可以这样做: 如何在Python中做类似的事情? 问题答案: 用以下方式注册你的处理程序: 代码改编自此处。

  • 在我的Java控制台应用程序中,我按下Ctrl C键并添加一个线程,使用Runtime.getRuntime(). addShutdownHook()执行优雅的关机 在这个线程中,我处理一些内部队列中的所有遗留工作,并优雅地退出我的应用程序,这通常是我想要的。 然而,有时应用程序可能会有需要一段时间(几分钟)才能处理的内部队列,如果是这样的话,我希望有一个选项可以再次按Ctrl C以强制退出应用程

  • 问题内容: 我正在阅读出色的在线书籍http://nodebeginner.org/,并尝试了简单的代码 现在我不知道(而且我仍然不知道!)如何优雅地关闭node.js,所以我就去了。现在,每次我尝试运行时,都会收到以下错误消息。 因此,有两个问题: 1)如何正常关闭node.js? 2)如何修复我创建的混乱? 问题答案: 使用+ 优雅地退出节点进程 清理混乱取决于您的平台,但基本上,您需要找到运

  • 我有一个程序,我在其中构建了一个ffmpeg命令字符串,以捕获通过gtk3 GUI输入的选项视频。一旦选择了所有选项,我就会生成一个带有ffmpeg命令字符串的进程。我添加了一个儿童手表来告诉我什么时候该过程已经完成。 使用命令行从终端执行ffmpeg,程序将提供一个选项,在终端输入一个“Q”,以提前结束ffmpeg过程。是否有任何方法可以发送一个“Q”到这个产生的进程,以优雅地结束FFMPEG?

  • 问题内容: 是否可以在Java命令行应用程序中捕获+ 信号?我想在终止程序之前清理一些资源。 问题答案: 您可以将关闭挂钩连接到VM,只要VM关闭,该挂钩便会运行: Java虚拟机将响应以下两种事件而关闭: 当最后一个非守护程序线程退出时,或者调用exit(等效于System.exit)方法时,程序将正常退出,或者 响应于用户中断(例如键入+ )或系统范围的事件(例如用户注销或系统关闭)来终止虚拟