为什么在SIGTERM中使用threading.Event结果没被捕获?

时间:2010-06-23 13:44:56

标签: python events multithreading signals daemon

我有一个线程化的Python守护进程。像任何好的守护进程一样,它想要启动它的所有工作线程,然后等待它被告知终止。终止的正常信号是SIGTERM,在大多数语言中我都会通过等待事件或互斥来终止,因此使用threading.Event对我有意义。问题是Python的Event对象和Unix信号似乎没有很好地一起播放。

这可以按预期工作,终止于SIGTERM

import signal
import time

RUN = True

def handle(a, b):
    global RUN
    print "handled"
    RUN = False

signal.signal(signal.SIGTERM, handle)
while RUN:
    time.sleep(0.250)
print "Stopping"

但是这导致没有传递SIGTERM(即,除了退出之外,“处理”永远不会被打印):

import signal
import threading

RUN_EVENT = threading.Event()

def handle(a, b):
    print "handled"
    RUN_EVENT.set()

signal.signal(signal.SIGTERM, handle)
RUN_EVENT.wait()
print "Stopping"

所以我的问题是:

  1. 我是否以某种方式滥用threading.Event
  2. 如果我不是,除了第一个例子中的民意调查和睡眠机制之外还有其他选择吗?
  3. 如果我不是,为什么使用threading.Event杀死信号处理程序?

2 个答案:

答案 0 :(得分:14)

来自Python documentation on signals

  

尽管就Python用户而言,Python信号处理程序是异步调用的,但它们只能出现在Python解释器的“原子”指令之间。这意味着在纯C中实现的长计算期间到达的信号(例如大文本上的正则表达式匹配)可能会延迟一段任意时间。

我测试了各种threadingthread类,但没有一个按照你想要的方式工作 - 这可能是因为Python处理信号的方式。

然而,在signal中,有一个pause()函数在进程收到信号之前休眠。您修改后的示例如下所示:

import signal

RUN = True

def handle(a, b):
    global RUN
    print "handled"
    RUN = False

signal.signal(signal.SIGTERM, handle)
while RUN:
    signal.pause()
print "Stopping"

我在Linux上查了一下,确实有效。如果您的应用程序不使用大量其他信号,我认为它不再归类为轮询和睡眠。

答案 1 :(得分:0)

在Python 3中有效:

from threading import Event
from os import getpid
from signal import SIGTERM, SIGINT, signal

stop_event = Event()

def handler(signum, frame):
    stop_event.set()

def main():
    signal(SIGTERM, handler)
    signal(SIGINT, handler)
    print('start, pid:', getpid())
    stop_event.wait()
    print('done')

if __name__ == '__main__':
    main()

看来,在 Python 2.7 中,它只有在指定等待间隔时才有效:stop_event.wait(number_of_seconds)