2010-06-23 34 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

相關問題