Python和信号处理程序

时间:2018-09-12 09:23:16

标签: python signals python-multithreading python-asyncio

我需要对python中的信号处理程序进行一些澄清,因为我不能精确地了解它们的工作方式,使用方式以及局限性。

我打算在Linux上使用USR信号,以便与作为服务在后台运行的python程序进行通信。

我发现,按照预期,我发送的信号似乎立即以异步方式处理。

因此,我曾经以为注册的信号处理程序在自己的线程中运行,我认为这将解释为什么以下代码在循环发送信号时为何一次打印多行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信号处理程序也总是在主Python线程中执行”。另外,对于上述示例,我没有看到在系统上运行单独的线程。

我现在想知道,我使用信号方法的实际含义和局限性是什么,以及我如何正确地做相关的事情,例如被调用的信号处理程序实例之间的通信。

例如,在某些情况下,我希望能够延迟信号处理程序中某些代码的执行,直到处理完相同类型的先前信号为止。 我也不知道将“并行”处理多少个信号,当“队列”已满时会发生什么...

我一直在研究Pyhton的asyncio,它似乎提供了一些对异步代码的控制,并且还带来了自己的注册信号处理程序的方式。它似乎提供了一些帮助,但是,它似乎并没有太大帮助,因为我所看到的行为(信号蜂收到信号时处理得很好)实际上是我想要的。我已经看到使用asyncio信号处理程序似乎可以在事件循环中执行信号。在我开始使用的部分阻止的代码中,可能为时已晚。我可以在单独的线程中运行其中一些代码(使用相应的asyncio函数),但不能使整个代码保持非阻塞状态。

1 个答案:

答案 0 :(得分:2)

  

我打算在Linux上使用USR信号,以便与作为服务在后台运行的python程序进行通信。

听起来像是一个非常糟糕的主意。原因如下:

  • Unix信号是异步传递的,这意味着您可以在任何库代码运行时(例如在malloc调用过程中)获得信号。因此,async-signal-safe仅使用少量函数,即可以安全地从信号处理程序调用。 Python代码根本无法在信号处理程序内执行,因此signal.signal设置的处理程序不会执行Python函数,而只是设置一个全局标志。主线程会不时检查此标志,该主线程会执行Python处理函数。这意味着不能保证信号会立即发送,即您不能依靠操作系统提供的信号发送保证。

  • 信号可能在执行前一个信号的处理程序期间到达。这就是为什么您看到多行打印的原因,这是信号处理程序本身被信号打断并重新进入的假象。

  • 除非您使用专用的POSIX调用设置信号处理程序(并且使用这些调用设置的处理程序不能直接执行Python代码),否则信号不会排队。即使它们处于排队状态,除了非实时信号外,信号在生成和传送之间的顺序也不会保留。

  • 即使在纯C语言中,信号与多线程代码的交互也非常糟糕。

如果您需要与之通信的服务,则可以有一个从命名管道读取或在套接字上侦听的线程。写入管道或打开插座,将成为该过程的信号。这还允许将其他信息传递给服务。