Python多处理 - 向子进程发送输入

时间:2013-07-08 08:58:33

标签: python bash multiprocessing

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

如何确定是否有任何子进程正在等待用户输入,以及如何向其发送“exit”命令?任何指向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()

1 个答案:

答案 0 :(得分:0)

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

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

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

subprocess.call()函数只是构造subprocess.Popen实例然后在其上调用wait()方法的简写。因此,您的备用进程可以创建自己的subprocess.Popen实例,并使用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或类似的情况下运行一个进程,但这是一个非常糟糕的黑客,我真的不会推荐它。 strace之类的东西非常适合手动诊断,但它们确实不应该是生产设置的一部分。