Python 中的信号处理允许你定义自定义处理器来管理诸如来自键盘的中断或终止请求等异步事件、警报甚至是系统信号。你可以通过定义自定义处理器来控制程序如何响应各种信号。Python 中的 signal
模块提供了设置和管理信号处理器的机制。
信号处理器是一个当接收到特定信号时会被执行的函数。signal.signal()
函数允许定义信号的自定义处理器。signal
模块提供了一种方式来定义当接收到特定信号时将会被执行的自定义处理器。Python 中已经安装了一些默认的处理器,包括但不限于:
-
-
SIGINT
被转换成 KeyboardInterrupt
异常。
常见信号
Python 信号处理器在主解释器的主线程中执行,即使信号是在其他线程中接收到的。信号不能用于线程间通信。
以下是一些常见的信号及其默认动作列表:
-
SIGINT
— 键盘中断(Ctrl+C),引发 KeyboardInterrupt
。
-
-
SIGALRM
— 来自 alarm()
的定时器信号。
-
-
SIGUSR1
和 SIGUSR2
— 用户定义的信号。
设置信号处理器
为了设置一个信号处理器,我们可以使用 signal.signal()
函数。它允许你为信号定义自定义处理器。除非明确重置,否则处理器会一直安装着,除了 SIGCHLD
。
示例
下面是一个使用 signal.signal()
函数设置 SIGINT
处理器的例子。
import signal
import time
def handle_signal(signum, frame):
print(f"接收到信号 {signum}")
signal.signal(signal.SIGINT, handle_signal)
print("按下 Ctrl+C 触发 SIGINT")
while True:
time.sleep(1)
输出
执行上述程序,你将得到如下结果:
按下 Ctrl+C 触发 SIGINT
信号 2 收到
信号 2 收到
信号 2 收到
信号 2 收到
在 Windows 上的信号处理
在 Windows 上,signal.signal()
函数只能处理有限的一组信号。如果你尝试使用 Windows 上不支持的信号,则会抛出 ValueError
。如果信号名称未定义为 SIG*
模块级别的常量,则会抛出 AttributeError
。
Windows 上支持的信号如下:
处理计时器和警报
计时器和警报可以用来在一段时间之后安排信号的传递。
示例
下面是一个处理警报的例子。
import signal
import time
def handler(signum, stack):
print('警报:', time.ctime())
signal.signal(signal.SIGALRM, handler)
signal.alarm(2)
time.sleep(5)
for i in range(5):
signal.alarm(2)
time.sleep(5)
print("中断 #%d" % i)
输出
执行上述程序,你将得到如下结果:
警报: Wed Jul 17 17:30:11 2024
警报: Wed Jul 17 17:30:16 2024
中断
警报: Wed Jul 17 17:30:21 2024
中断
警报: Wed Jul 17 17:30:26 2024
中断
警报: Wed Jul 17 17:30:31 2024
中断
警报: Wed Jul 17 17:30:36 2024
中断
从数字获取信号名称
Python 中没有直接从数字获取信号名称的方式。你可以使用 signal
模块来获取所有它的属性,过滤出那些以 SIG
开始的,并存储在一个字典中。
示例
下面的例子创建了一个字典,其中键是信号号,值是相应的信号名。这在动态解析信号号时很有用。
import signal
sig_items = reversed(sorted(signal.__dict__.items()))
final = dict((k, v) for v, k in sig_items if v.startswith('SIG') and not v.startswith('SIG_'))
print(final)
输出
执行上述程序,你将得到如下结果:
{
<Signals.SIGXFSZ: 25>: 'SIGXFSZ',
<Signals.SIGXCPU: 24>: 'SIGXCPU',
<Signals.SIGWINCH: 28>: 'SIGWINCH',
<Signals.SIGVTALRM: 26>: 'SIGVTALRM',
<Signals.SIGUSR2: 12>: 'SIGUSR2',
<Signals.SIGUSR1: 10>: 'SIGUSR1',
<Signals.SIGURG: 23>: 'SIGURG',
<Signals.SIGTTOU: 22>: 'SIGTTOU',
<Signals.SIGTTIN: 21>: 'SIGTTIN',
<Signals.SIGTSTP: 20>: 'SIGTSTP',
<Signals.SIGTRAP: 5>: 'SIGTRAP',
<Signals.SIGTERM: 15>: 'SIGTERM',
<Signals.SIGSYS: 31>: 'SIGSYS',
<Signals.SIGSTOP: 19>: 'SIGSTOP',
<Signals.SIGSEGV: 11>: 'SIGSEGV',
<Signals.SIGRTMIN: 34>: 'SIGRTMIN',
<Signals.SIGRTMAX: 64>: 'SIGRTMAX',
<Signals.SIGQUIT: 3>: 'SIGQUIT',
<Signals.SIGPWR: 30>: 'SIGPWR',
<Signals.SIGPROF: 27>: 'SIGPROF',
<Signals.SIGIO: 29>: 'SIGIO',
<Signals.SIGPIPE: 13>: 'SIGPIPE',
<Signals.SIGKILL: 9>: 'SIGKILL',
<Signals.SIGABRT: 6>: 'SIGABRT',
<Signals.SIGINT: 2>: 'SIGINT',
<Signals.SIGILL: 4>: 'SIGILL',
<Signals.SIGHUP: 1>: 'SIGHUP',
<Signals.SIGFPE: 8>: 'SIGFPE',
<Signals.SIGCONT: 18>: 'SIGCONT',
<Signals.SIGCHLD: 17>: 'SIGCHLD',
<Signals.SIGBUS: 7>: 'SIGBUS',
<Signals.SIGALRM: 14>: 'SIGALRM'
}