2014-03-06 38 views
2

我有一個長期運行的Python進程,我希望能夠在它掛起並停止報告進度的情況下終止。但是我想用一種能夠安全清理的方式發出信號,以防萬一它沒有完全掛斷,並且還有一些東西可以正常響應信號。直接殺死它之前發送信號的最佳順序是什麼?正確的信號順序來安全地停止進程

目前,我正在做這樣的事情:

def safe_kill(pid): 
    for sig in [SIGTERM, SIGABRT, SIGINT, SIGKILL]: 
     os.kill(pid, sig) 
     time.sleep(1) 
     if not pid_exists(pid): 
      return 

是否有更好的秩序?我知道SIGKILL完全繞過了這個過程,但是在SIGTERM/SIGABRT/SIGINT之間有沒有什麼重大區別,或者就Python而言它們都具有相同的效果?

+0

如果您希望在任何這些信號之後進行清理,您將需要註冊信號處理程序的過程。我不認爲Python會將其中的任何一個變成例外;它只是停止。 – user2357112

+0

我認爲這裏的答案取決於你試圖優雅地殺死的python進程 - 它是否註冊任何信號處理程序?如果是這樣,他們記錄在案嗎?如果它沒有註冊任何處理程序,那麼我想它並不重要你先發送什麼;-) – mgilson

+0

@ user2357112 - SIGINT變成了'KeyboardInterrupt' IIRC ... – mgilson

回答

2

我相信停止進程的正確方法是SIGTERM,緊接着是一個小超時後的SIGKILL。

如果該過程以標準方式處理信號,我認爲不需要SIGINT和SIGABRT。 SIGINT通常以與SIGTERM和SIGABRT相同的方式進行處理,通常由進程本身在abort()(wikipedia)上使用。

任何比小腳本更復雜的東西通常會實現自定義的SIGTERM處理以便正常關閉(清理所有資源等)。

例如,看看Upstart。它是一個init守護進程 - 啓動和停止Ubuntu和其他一些發行版中的大部分進程。用於停止進程的默認Upstart行爲是發送SIGTERM,等待5秒併發送SIGKILL(源 - upstart cookbook)。

您可能應該進行一些測試以確定您的流程的最佳超時時間。

1

您需要註冊一個信號處理程序,因爲你會做C.

import signal 
import sys 

def clean_termination(signal): 
    # perform your cleanup 
    sys.exit(1) 

# register the signal handler for the signals specified in the question 
signal.signal(signal.SIGTERM, clean_termination) 
signal.signal(signal.SIGABRT, clean_termination) 

需要注意的是Python的映射SIGINT信號到KeyboardInterrupt例外,那你可以用定期except聲明趕上。