Python 中的信号处理允许您定义自定义处理程序,用于管理异步事件,例如来自键盘的中断或终止请求、警报甚至系统信号。您可以通过定义自定义处理程序来控制程序对各种信号的响应方式。Python 中的 signal 模块提供了设置 and management signal handlers 的机制。
信号处理程序是在接收到特定信号时执行的函数。signal.signal() 函数允许为信号定义自定义处理程序。信号模块提供了一种定义自定义处理程序的方法,这些处理程序将在接收到特定信号时执行。Python 中已经安装了一些默认处理程序,它们是 -
- SIGPIPE 被忽略。
- SIGINT 转换为 KeyboardInterrupt 异常。
常用信号
Python 信号处理程序在主解释器的主 Python 线程中执行,即使信号是在另一个线程中接收的。信号不能用于线程间通信。
以下是一些常见信号及其默认操作的列表 -
- SIGINT − 来自键盘的中断 (Ctrl+C),这会引发 KeyboardInterrupt。
- SIGTERM − 终止信号。
- SIGALRM− 来自 alarm() 的计时器信号。
- SIGCHLD - 子进程已停止或终止。
- SIGUSR1 和 SIGUSR2 − 用户定义的信号。
设置 Signal Handler
要设置信号处理程序,我们可以使用 signal.signal() 函数。它允许您为 signals 定义自定义处理程序。处理程序将保持安装状态,直到显式重置,SIGCHLD 除外。
例下面是一个使用 signal.signal() 函数和 SIGINT 处理程序设置信号处理程序的示例。
import signal
import time
def handle_signal(signum, frame):
print(f"Signal {signum} received")
# Setting the handler for SIGINT
signal.signal(signal.SIGINT, handle_signal)
print("Press Ctrl+C to trigger SIGINT")
while True:
time.sleep(1)
输出
在执行上述程序时,您将获得以下结果 -
Signal 2 received
Signal 2 received
Signal 2 received
Signal 2 received
Windows 上的信号处理
在 Windows 上,signal.signal() 函数只能处理一组有限的信号。如果尝试使用 Windows 不支持的信号,则会引发 ValueError。而且,如果信号名称未定义为 SIG* 模块级常量,将引发 AttributeError。
Windows 上支持的信号如下 -
- SIGABRT
- SIGFPE
- SIGILL
- SIGINT
- SIGSEGV
- SIGTERM
- SIGBREAK
处理计时器和警报
计时器和警报可用于安排在一定时间后传输信号。
例我们来观察以下处理告警的示例。
import signal
import time
def handler(signum, stack):
print('Alarm: ', 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("interrupted #%d" % i)
输出
在执行上述程序时,您将获得以下结果 -
Alarm: Wed Jul 17 17:30:16 2024
interrupted #0
Alarm: Wed Jul 17 17:30:21 2024
interrupted #1
Alarm: Wed Jul 17 17:30:26 2024
interrupted #2
Alarm: Wed Jul 17 17:30:31 2024
interrupted #3
Alarm: Wed Jul 17 17:30:36 2024
interrupted #4
从 Numbers 获取 Signal Names
在 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)
输出
在执行上述程序时,您将获得以下结果 -