我有一个线程化的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"
所以我的问题是:
threading.Event
?threading.Event
杀死信号处理程序?答案 0 :(得分:14)
来自Python documentation on signals:
尽管就Python用户而言,Python信号处理程序是异步调用的,但它们只能出现在Python解释器的“原子”指令之间。这意味着在纯C中实现的长计算期间到达的信号(例如大文本上的正则表达式匹配)可能会延迟一段任意时间。
我测试了各种threading
和thread
类,但没有一个按照你想要的方式工作 - 这可能是因为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)