【问题标题】:Reliably terminating subprocess on Python 2.5在 Python 2.5 上可靠地终止子进程
【发布时间】:2011-10-31 14:12:34
【问题描述】:

我有一个脚本,它反复运行 Ant 构建文件并将输出刮成可解析的格式。当我使用 Popen 创建子进程时,有一个小时间窗口,按 Ctrl+C 将杀死脚本,但不会杀死运行 Ant 的子进程,留下一个僵尸,它正在打印输出到控制台,只能使用 Task 杀死经理。一旦 Ant 开始打印输出,按 Ctrl+C 总是会杀死我的脚本以及 Ant。有没有办法让按 Ctrl+C 总是会杀死运行 Ant 的子进程而不会留下僵尸?

另外值得注意的是:我有一个 SIGINT 处理程序,它在调用 exit(0) 之前执行一些清理操作。如果我使用os.kill(p.pid, signal.SIGTERM)(不是SIGINT)手动终止处理程序中的子进程,那么我可以在通常会僵尸化的情况下成功终止子进程。但是,一旦 Ant 开始产生输出,当您按 Ctrl+C 时,您会从子进程中获得一个堆栈跟踪,它无法杀死子进程本身,因为我已经杀死了它。


编辑:我的代码看起来像:

p = Popen('ls')
def handle_sig_int(signum, stack_frame):
    # perform cleanup
    os.kill(p.pid, signal.SIGTERM)
    exit(0)
signal.signal(signal.SIGINT, handle_sig_int)

p.wait()

错误触发时会产生以下堆栈跟踪:

File "****.py", line ***, in run_test
  p.wait()
File "/usr/lib/python2.5/subprocess.py", line 1122, in wait
  pid, sts = os.waitpid(self.pid, 0)
File "****.py", line ***, in handle_sig_int
  os.kill(p.pid, signal.SIGTERM)

我通过捕获 p.wait 引发的 OSError 并退出来修复它:

try:
    p.wait()
except OSError:
    exit('The operation was interrupted by the user')

这似乎在我的绝大多数测试运行中都有效。我偶尔会收到uname: write error: Broken pipe,虽然我不知道是什么原因造成的。如果我在子进程开始显示输出之前按 Ctrl+C 计时,似乎会发生这种情况。

【问题讨论】:

    标签: python subprocess


    【解决方案1】:

    在您的 SIGTERM 处理程序中调用 p.terminate()

     if p.poll() is None: # Child still around?
         p.terminate() # kill it
    

    [编辑] 由于您一直使用 Python 2.5,因此请使用 os.kill(p.pid, signal.SIGTERM) 而不是 p.terminate()。检查应确保您没有遇到异常(或减少您获得异常的次数)。

    为了使它更好,您可以捕获异常并检查消息。如果它表示“未找到子进程”,则忽略该异常。否则,用raise(无参数)重新抛出它。

    【讨论】:

    • 在我意识到 p.terminate() 是在 Python 2.6 中添加之前,我最初尝试过的,而我被困在 2.5 中。很遗憾,我无法升级 Python。
    • 我终于设法通过尝试调用 p.wait() 并在捕获到 OSError 时出错退出。
    猜你喜欢
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    • 2015-09-07
    相关资源
    最近更新 更多