2010-06-23 73 views
14

我有一个线程化的Python守护进程。像任何好的守护进程一样,它想要启动它的所有工作线程,然后等待,直到告知终止。终止的正常信号是SIGTERM,并且在大多数语言中,我会坚持通过等待事件或互斥体来终止,因此使用threading.Event对我而言意义重大。问题在于Python的Event对象和Unix信号看起来并没有很好地一起玩。为什么使用threading.Event导致SIGTERM不被捕获?

可正常工作,终止于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. 如果我不是,除了第一个例子中的poll-and-sleep机制,还有其他的选择吗?
  3. 另外,如果我不是,为什么使用threading.Event杀死信号处理程序?

回答

13

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上检查过它,它工作正常。如果您的应用程序不使用很多其他信号,我认为它不再被分类为轮询和睡眠。

+0

Python的烦人的功能,但完美的解决方案。谢谢。我承认我没有想到在'signal'的使用上寻找额外的限制,因为我知道等价的C将会正常工作。 – 2010-06-23 17:14:17

+3

这是否意味着处理信号的唯一方法是专用主线程(父)捕获信号(通过阻塞'signal.pause()')?这意味着主线程不能再做任何有用的事情。换句话说,你不可能有一个主/辅模型(2个线程相互对话),但你需要一个主/辅助+工作者模型(2个工作人员彼此交谈,主人不做任何事情。 – 2013-01-16 22:42:00

相关问题