Python 脚本中有多个 SIGTERM 处理程序 - 谁应该调用 sys.exit()?

More than one SIGTERM handler in a Python script - who should call sys.exit()?

假设我有以下脚本:

import signal
import sys

class Klass:
   def __init__(self, name):
     self.name = name

     def disconnect_gracefully(*args):
         print(self.name)
         sys.exit()

     signal.signal(signal.SIGINT, disconnect_gracefully)


a = Klass("A")
b = Klass("B")

while True:
    pass

请注意,两个 类 在 SIGINT 之后都会正常退出。当我 运行 this 和 crtl-c 时,只打印“B”。

一般来说,在这种情况下,whowhat 应该调用 sys.exit() - 两个实例都应该调用吗?

signal 的 Python 文档仅说明当您多次为同一信号设置处理程序时会发生什么:

A handler for a particular signal, once set, remains installed until it is explicitly reset

[when calling signal.signal] The previous signal handler will be returned

这似乎意味着,就像 POSIX 信号一样,一个进程一次只能有一个给定信号的处理程序。

我们可以在您的程序中添加一些语句来显示 signal.signal returns(在 CPython 中):

import signal
import sys
class K:
  def __init__(self, name):
    self.name=name
    def disconnect(*args):
      print(self.name)
      sys.exit()
    self.disconnectfuncid=id(disconnect)
    self.oldsig=signal.signal(signal.SIGINT, disconnect)


>>> a=K("a")
>>> hex(a.disconnectfuncid)
'0x7fc5c1057f28'
>>> a.oldsig
<built-in function default_int_handler>
>>> signal.getsignal(signal.SIGINT)
<function K.__init__.<locals>.disconnect at 0x7fc5c1057f28>


>>> b=K("b")
>>> hex(b.disconnectfuncid)
'0x7fc5c0ed0950'
>>> b.oldsig
<function K.__init__.<locals>.disconnect at 0x7fc5c1057f28>
>>> signal.getsignal(signal.SIGINT)
<function K.__init__.<locals>.disconnect at 0x7fc5c0ed0950>


>>> while True:
...   pass
...^C b

所以处理程序开始为 <built-in function default_int_handler>,然后设置为 a 实例中的 disconnect 函数,然后设置为 disconnect 实例中的 disconnect 函数b 实例,后者是在传递信号时调用的实例。

如果你想在接收到 SIGINT 时退出,并且 运行 在退出前有多个函数,一种方法是调用以下命令(这将禁止打印回溯和 KeyboardInterrupt 消息):

 signal.signal(signal.SIGINT, lambda *args: sys.exit())

然后使用atexit.register注册每个函数。