0

我正在使用 python 中的多处理模块来并行启动几个进程。这些过程是相互独立的。他们生成自己的输出并将结果写在不同的文件中。每个进程使用 subprocess.call 方法调用一个外部工具。它工作正常,直到我在外部工具中发现一个问题,由于某些错误情况,它进入“提示”模式并等待用户输入。现在在我的 python 脚本中,我使用 join 方法等待所有进程完成它们的任务。这导致整个事情等待这个错误的子进程调用。我可以为每个进程设置一个超时,但我事先不知道每个进程将运行多长时间,因此排除了此选项。

如何确定是否有任何子进程正在等待用户输入以及如何向其发送“退出”命令?对python中相关模块的任何指针或建议将不胜感激。

我的代码在这里:

import subprocess
import sys
import os
import multiprocessing

def write_script(fname,e):
    f = open(fname,'w')
    f.write("Some useful cammnd calling external tool")
    f.close()
    subprocess.call(['chmod','+x',os.path.abspath(fname)])
    return os.path.abspath(fname)

def run_use(mname,script):
    print "ssh "+mname+" "+script
    subprocess.call(['ssh',mname,script])

if __name__ == '__main__':
    dict1 = {}
    dict['mod1'] = ['pp1','ext2','les3','pw4']
    dict['mod2'] = ['aaa','bbb','ccc','ddd']
    machines = ['machine1','machine2','machine3','machine4']
    log_file.write(str(dict1.keys()))
    for key in dict1.keys():
        arr = []
        for mod in dict1[key]:
            d = {}
            arr.append(mod)
            if ((mod == dict1[key][-1]) | (len(arr)%4 == 0)):
                for i in range(0,len(arr)):
                    e = arr.pop()
                    script  = write_script(e+"_temp.sh",e)
                    d[i] = multiprocessing.Process(target=run_use,args=(machines[i],script,))
                    d[i].daemon = True
                for pp in d:
                    d[pp].start()
                for pp in d:
                    d[pp].join()
4

1 回答 1

0

由于您正在编写一个 shell 脚本来运行您的子命令,您可以简单地告诉他们从 读取输入/dev/null吗?

#!/bin/bash
# ...
my_other_command -a -b arg1 arg2 < /dev/null
# ...

这可能会阻止他们阻止输入,并且是一个非常简单的解决方案。如果这对您不起作用,请继续阅读其他一些选项。

subprocess.call()函数只是构造subprocess.Popen实例然后wait()在其上调用方法的简写。因此,您的备用进程可以改为创建自己的实例并使用对象上的方法而不是(在具有适当延迟的循环中)subprocess.Popen轮询它们。这使它们可以自由地与主进程保持通信,例如,您可以允许主进程告诉子进程使用or方法终止实例,然后自行退出。poll()wait()Popenterminate()kill()

所以,问题是子进程如何判断子进程是否正在等待用户输入,这是一个更棘手的问题。我想说也许最简单的方法是监视子进程的输出并搜索用户输入提示,假设它总是使用一些您可以查找的字符串。或者,如果子进程预计会持续生成输出,那么您可以简单地查找任何输出,并且如果配置的时间过去没有任何输出,那么您声明该进程已终止并如上所述终止它。

由于您正在读取输出,实际上您不需要poll()wait()- 关闭其输出文件描述符的进程足以知道它在这种情况下已终止。

下面是一个修改后的run_use()方法的例子,它监视子进程的输出:

def run_use(mname,script):
    print "ssh "+mname+" "+script
    proc = subprocess.Popen(['ssh',mname,script], stdout=subprocess.PIPE)
    for line in proc.stdout:
        if "UserPrompt>>>" in line:
            proc.terminate()
            break

在此示例中,我们假设进程要么挂起UserPrompt>>>(替换为适当的字符串),要么自然终止。例如,如果它陷入无限循环,那么您的脚本仍然不会终止 - 您只能通过整体超时来真正解决这个问题,但您似乎并不热衷于这样做。但是,希望您的子流程不会以这种方式行为不端。

最后,如果您事先不知道您的流程将给出的提示,那么您的工作就更难了。实际上,您要求做的是监视外部进程并知道它何时被阻止读取文件描述符,我不相信对此有特别干净的解决方案。您可以考虑在下或类似下运行一个进程strace,但这是一个非常糟糕的 hack,我真的不推荐它。诸如此类的东西strace非常适合手动诊断,但它们确实不应该成为生产设置的一部分。

于 2013-07-08T11:44:33.817 回答