【问题标题】:Python script being stopped after a subprocess is completed子进程完成后 Python 脚本被停止
【发布时间】:2019-07-12 04:49:02
【问题描述】:

在运行我的脚本时,我正在动态运行一组 for 循环。基本上是调用一个项目列表,检查该项目需要在哪个“阶段”运行,然后按该顺序运行它们。当我尝试运行这些循环时,它会通过第一个对象,然后在终端中给出“[1]+ Stopped Script.py”。我找到了开始备份我的脚本的方法,但没有关于如何完全避免这种情况发生的帖子。

我尝试过使用Popencallcheck_output 等。它们都得到相同的结果。我确信这是我正在调用的另一个项目在它的末尾执行此操作,但我认为关闭的另一个程序不会杀死我的脚本,尤其是在子进程中。

我也尝试过使用线程和多处理。两者都无济于事。

def foo(list):
    stages = 0
    for c in things:
        info = load_json_info(c)
        if info["stage"] >= stages:
            stages = info["stage"]
    for p in list:
        use_list(p)
    stages = stages + 1
    for i in range(stages):
        for b in list:
            info = load_json_info(b)
            if info["stage"] == i:
                if info["check"] != "NO":
                    output = call("command", shell=True)
                    if output == 0:
                        DO_THING()
                    else:
                        DONT_DO_THING()
                else:
                    DONT_DO_THING()

它到达DO_THING() 并经历了所有这些,然后当需要调用另一个子进程时,它又死了。该子进程是否存在于DO_THING() 中,或者我将所有内容都注释掉,然后让它再次访问output = call("command", shell=True) 行。一旦它再次使用子进程,它就会停止。

人们有什么建议或方法可以阻止正在传递的内容以阻止我的脚本?

(提醒一下,我无法访问导致我的脚本停止的"command" 的源代码,而我正在使用的"command" 并不重要,因为我对此无能为力结束。我也必须使用这个"command"。)

【问题讨论】:

  • 您的 python 中是否收到错误消息?您确定没有阻止命令再次运行,所以您的脚本只是飞过列表并结束吗?

标签: python subprocess


【解决方案1】:

您看到的消息表明您的子进程正在停止,而不是出现错误。例如,在 shell 中启动进程后键入 Ctrl-Z 时会发生这种情况,或者等效地,使用 kill 命令向目标进程发送 SIGTSTP 信号时会发生这种情况。据推测,您无权访问的command 正在接收此信号。它甚至可以将其发送给自己,尽管在不了解该命令的更多信息的情况下,它只是推测发生这种情况的方式或原因。

您可以选择在 Python 中使用signal 模块,特别是pthread_sigmask() 函数来忽略此信号。一个指定信号掩码,以及如何处理它们。在这种情况下,您想忽略SIGTSTP 信号,可以使用:signal.pthread_sigmask(signal.SIG_BLOCK, (signal.SIGTSTP,))。 (后一个参数实际上是一系列要忽略的信号。)

运行这段sn-p代码,你应该看到你可以在终端输入Ctrl-Z,shell应该会显示[1]+ Stopped ...

import time
duration = 5.0
print('Sleeping for {:0.2f} seconds'.format(duration))
time.sleep(duration)

但是,使用下面的代码,我们会看到信号被忽略了,进程将继续“工作”(在这种情况下是休眠),而不管信号如何。每当您按 Ctrl-Z 时,您应该只会在 shell 中看到 ^Z

import time
import signal
duration = 5.0
print('Sleeping for {:0.2f} seconds, ignoring SIGTSTP'.format(duration))
signal.pthread_sigmask(signal.SIG_BLOCK, (signal.SIGTSTP,))
time.sleep(duration)

要在脚本中实际使用它,请在调用相关的command 之前忽略该信号。最好事先查询进程的信号掩码,并在完成command 后将其重置为该值。您应该查看signal(3)sigprocmask(2)kill(2) 的手册页以了解有关信号和过程的更多信息。

为 Python 编辑

signal.pthread_sigmask 在 Python 3.3 中添加。应该适用于早期版本的解决方案是直接忽略信号,方法是安装一个处理程序来执行此操作。例如:

import signal
import time

duration = 5.0
signal.signal(signal.SIGTSTP, signal.SIG_IGN)
print 'Sleeping for %f seconds, ignoring SIGTSTP' % duration
time.sleep(duration)

与上面的 3.3 示例一样,如果您点击 Ctrl-Z,您应该只会看到 ^Z,这表明信号被忽略了。

【讨论】:

  • 遗憾的是,我正在运行“Python 2.7.10”。这个项目太深入了,现在不能升级它。您知道可以在 3.3 之前使用的方法吗?
  • @Kakuga 添加了一个适用于 2.7 的编辑版本。