Python 和信号处理程序
Python and signal handlers
我需要对 python 中的信号处理程序进行一些说明,因为我不完全了解它们的工作原理、使用方法以及限制。
我打算在 linux 上使用 USR 信号,以便与 python 程序 运行ning 在后台作为服务进行通信。
我发现,正如预期的那样,我发送的信号似乎以异步方式立即得到处理。
因此,我曾经认为注册的信号处理程序 运行 在它们自己的线程中,我认为这可以解释为什么以下代码在发送时会一次打印多行 Signal handler called with signal 10
循环中的信号
#!/usr/bin/python3.5
# This is the file signal_example.py
import signal, time, os
def handler(signum, frame):
print('Signal handler called with signal', signum)
time.sleep(20)
signal.signal(signal.SIGUSR1, handler)
time.sleep(100)
#!/usr/bin/bash
for ((i=0;i<100;i=i+1)); do
killall -s SIGUSR1 signal_example.py;
done
但是,文档说明 (https://docs.python.org/3.4/library/signal.html) "Python signal handlers are always executed in the main Python thread, even if the signal was received in another thread."。此外,对于上述示例,我在我的系统上没有看到单独的线程 运行ning。
我现在想知道,我使用信号的方法的实际含义和局限性是什么,以及我如何才能正确地做相关的事情,例如被调用的信号处理程序的实例之间的通信。
例如,在某些情况下,我希望能够延迟信号处理程序中某些代码的执行,直到处理完之前的同类信号为止。
我也不明白将处理多少信号 "in parallel" 以及当 "queue" 已满时会发生什么...
我一直在研究 Pyhton 的 asyncio
,它似乎提供了对异步代码的一些控制,并且还提供了自己的方式来注册信号处理程序。它似乎提供了一些帮助,但是,它似乎对我帮助不大,因为我看到的行为(信号在收到时几乎被处理)实际上是我想要的。我看到的 asyncio
信号处理程序的使用似乎是在事件循环中执行信号。在我开始使用的部分阻塞代码中,这可能为时已晚。我可以 运行 将其中的一些放在单独的线程中(使用相应的 asyncio
函数),但不能使整个代码成为非阻塞的。
I intend to use USR signals on linux in order to communicate with a python program running in the background as a service.
这听起来真是个坏主意。以下是几个原因:
Unix 信号是异步传递的,这意味着您可以在任何库代码处于 运行 时获得信号,例如在 malloc
调用的中间。出于这个原因,只有少数函数是 async-signal-safe,即可以安全地从信号处理程序调用。 Python 代码根本无法在信号处理程序内部执行,因此 signal.signal
设置的处理程序不会执行 Python 函数,而只是设置一个全局标志。该标志由主线程不时检查,主线程执行 Python 处理函数。这意味着不能保证信号会立即传递,即您不能依赖操作系统提供的信号传递保证。
信号可能在前一个信号的处理程序执行期间到达。这就是为什么您看到多行被打印出来的原因,这是信号处理程序本身被信号中断并重新进入的产物。
除非您使用专门的 POSIX 调用设置信号处理程序(并且使用这些调用设置的处理程序不能直接执行 Python 代码),信号不会排队.即使在排队时,除了非实时信号外,生成和传递之间的信号顺序也不会保留。
信号与多线程代码的交互非常糟糕,即使在纯 C 中也是如此。
如果您有需要与之通信的服务,您可以有一个从命名管道读取或在套接字上侦听的线程。写入管道或打开套接字将作为进程的信号。这也允许将附加信息传递给服务。
我需要对 python 中的信号处理程序进行一些说明,因为我不完全了解它们的工作原理、使用方法以及限制。
我打算在 linux 上使用 USR 信号,以便与 python 程序 运行ning 在后台作为服务进行通信。
我发现,正如预期的那样,我发送的信号似乎以异步方式立即得到处理。
因此,我曾经认为注册的信号处理程序 运行 在它们自己的线程中,我认为这可以解释为什么以下代码在发送时会一次打印多行 Signal handler called with signal 10
循环中的信号
#!/usr/bin/python3.5
# This is the file signal_example.py
import signal, time, os
def handler(signum, frame):
print('Signal handler called with signal', signum)
time.sleep(20)
signal.signal(signal.SIGUSR1, handler)
time.sleep(100)
#!/usr/bin/bash
for ((i=0;i<100;i=i+1)); do
killall -s SIGUSR1 signal_example.py;
done
但是,文档说明 (https://docs.python.org/3.4/library/signal.html) "Python signal handlers are always executed in the main Python thread, even if the signal was received in another thread."。此外,对于上述示例,我在我的系统上没有看到单独的线程 运行ning。
我现在想知道,我使用信号的方法的实际含义和局限性是什么,以及我如何才能正确地做相关的事情,例如被调用的信号处理程序的实例之间的通信。
例如,在某些情况下,我希望能够延迟信号处理程序中某些代码的执行,直到处理完之前的同类信号为止。 我也不明白将处理多少信号 "in parallel" 以及当 "queue" 已满时会发生什么...
我一直在研究 Pyhton 的 asyncio
,它似乎提供了对异步代码的一些控制,并且还提供了自己的方式来注册信号处理程序。它似乎提供了一些帮助,但是,它似乎对我帮助不大,因为我看到的行为(信号在收到时几乎被处理)实际上是我想要的。我看到的 asyncio
信号处理程序的使用似乎是在事件循环中执行信号。在我开始使用的部分阻塞代码中,这可能为时已晚。我可以 运行 将其中的一些放在单独的线程中(使用相应的 asyncio
函数),但不能使整个代码成为非阻塞的。
I intend to use USR signals on linux in order to communicate with a python program running in the background as a service.
这听起来真是个坏主意。以下是几个原因:
Unix 信号是异步传递的,这意味着您可以在任何库代码处于 运行 时获得信号,例如在
malloc
调用的中间。出于这个原因,只有少数函数是 async-signal-safe,即可以安全地从信号处理程序调用。 Python 代码根本无法在信号处理程序内部执行,因此signal.signal
设置的处理程序不会执行 Python 函数,而只是设置一个全局标志。该标志由主线程不时检查,主线程执行 Python 处理函数。这意味着不能保证信号会立即传递,即您不能依赖操作系统提供的信号传递保证。信号可能在前一个信号的处理程序执行期间到达。这就是为什么您看到多行被打印出来的原因,这是信号处理程序本身被信号中断并重新进入的产物。
除非您使用专门的 POSIX 调用设置信号处理程序(并且使用这些调用设置的处理程序不能直接执行 Python 代码),信号不会排队.即使在排队时,除了非实时信号外,生成和传递之间的信号顺序也不会保留。
信号与多线程代码的交互非常糟糕,即使在纯 C 中也是如此。
如果您有需要与之通信的服务,您可以有一个从命名管道读取或在套接字上侦听的线程。写入管道或打开套接字将作为进程的信号。这也允许将附加信息传递给服务。