安全停止进程的正确信号顺序

2 投票
2 回答
1778 浏览
提问于 2025-04-17 21:03

我有一个运行很久的Python程序,如果它卡住了,不再报告进度,我想能够终止它。不过,我希望以一种可以安全清理的方式来发出信号,这样如果它没有完全卡住,仍然有一些可以正常响应信号的部分在运行。那我应该先发哪些信号,再直接杀掉它呢?

我现在的做法是这样的:

def safe_kill(pid):
    for sig in [SIGTERM, SIGABRT, SIGINT, SIGKILL]:
         os.kill(pid, sig)
         time.sleep(1)
         if not pid_exists(pid):
             return

有没有更好的顺序呢?我知道SIGKILL是直接强制终止进程,但SIGTERM、SIGABRT和SIGINT之间有什么显著的区别吗?在Python看来,它们的效果都是一样的吗?

2 个回答

1

你需要注册一个信号处理器,就像在C语言中那样做。

import signal
import sys

def clean_termination(signal):
    # perform your cleanup
    sys.exit(1)

# register the signal handler for the signals specified in the question
signal.signal(signal.SIGTERM, clean_termination)
signal.signal(signal.SIGABRT, clean_termination)

需要注意的是,Python把信号映射成异常,你可以用普通的语句来捕捉这个异常。

2

我认为停止一个进程的正确方法是先发送SIGTERM信号,然后在稍微等一下后再发送SIGKILL信号。

如果那个进程以标准的方式处理信号,我觉得SIGINT和SIGABRT信号并不是必要的。SIGINT通常和SIGTERM处理方式相同,而SIGABRT通常是进程自己在调用abort()时使用的(维基百科)。

比起简单的脚本,复杂一点的程序通常会实现自定义的SIGTERM处理,以便优雅地关闭(比如清理所有资源等)。

举个例子,看看Upstart。它是一个初始化守护进程,负责在Ubuntu和其他一些发行版中启动和停止大多数进程。Upstart默认的停止进程的行为是先发送SIGTERM信号,等5秒钟,然后再发送SIGKILL信号(来源 - upstart手册)。

你可能需要进行一些测试,以确定适合你进程的最佳超时时间。

撰写回答