2014-03-06 37 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声明赶上。