简体   繁体   English

Python多重处理-将输入发送到子进程

[英]Python Multiprocessing - sending inputs to child processes

I am using the multiprocessing module in python to launch few processes in parallel. 我在python中使用多处理模块来并行启动几个进程。 These processes are independent of each other. 这些过程彼此独立。 They generate their own output and write out the results in different files. 他们生成自己的输出,并将结果写到不同的文件中。 Each process calls an external tool using the subprocess.call method. 每个进程都使用subprocess.call方法调用外部工具。 It was working fine until I discovered an issue in the external tool where due to some error condition it goes into a 'prompt' mode and waits for the user input. 直到我在外部工具中发现一个问题(由于某种错误情况导致该工具进入“提示”模式并等待用户输入)为止,它一直运行良好。 Now in my python script I use the join method to wait till all the processes finish their tasks. 现在,在我的python脚本中,我使用join方法等待所有进程完成其任务。 This is causing the whole thing to wait for this erroneous subprocess call. 这导致整个事情都在等待这个错误的子流程调用。 I can put a timeout for each of the process but I do not know in advance how long each one is going to run and hence this option is ruled out. 我可以为每个进程设置一个超时时间,但是我不事先知道每个进程将运行多长时间,因此该选项被排除在外。

How do I figure out if any child process is waiting for an user input and how do I send an 'exit' command to it? 我如何确定是否有任何子进程正在等待用户输入,以及如何向其发送“退出”命令? Any pointers or suggestions to relevant modules in python will be really appreciated. 真正感谢python中有关模块的任何指针或建议。

My code here: 我的代码在这里:

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()

Since you're writing a shell script to run your subcommands, can you simply tell them to read input from /dev/null ? 由于您正在编写Shell脚本来运行子命令,因此您能否简单地告诉它们从/dev/null读取输入?

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

This may stop them blocking on input and is a really simple solution. 这可能会阻止它们阻塞输入,这是一个非常简单的解决方案。 If this doesn't work for you, read on for some other options. 如果这对您不起作用,请继续阅读其他选项。

The subprocess.call() function is simply shorthand for constructing a subprocess.Popen instance and then calling the wait() method on it. subprocess.call()函数只是构造subprocess.Popen实例,然后在其上调用wait()方法的简写形式。 So, your spare processes could instead create their own subprocess.Popen instances and poll them with poll() method on the object instead of wait() (in a loop with a suitable delay). 因此,您的备用进程可以创建自己的subprocess.Popen实例,并在对象上使用poll()方法而不是wait()对其进行poll()以适当的延迟循环)。 This leaves them free to remain in communication with the main process so you can, for example, allow the main process to tell the child process to terminate the Popen instance with the terminate() or kill() methods and then itself exit. 这使它们可以自由地与主进程保持通信,因此,例如,您可以允许主进程告诉子进程使用Popen terminate()kill()方法终止Popen实例,然后自身退出。

So, the question is how does the child process tell whether the subprocess is awaiting user input, and that's a trickier question. 因此,问题是子流程如何分辨子流程是否在等待用户输入,这是一个棘手的问题。 I would say perhaps the easiest approach is to monitor the output of the subprocess and search for the user input prompt, assuming that it always uses some string that you can look for. 我想说,也许最简单的方法是监视子流程的输出并搜索用户输入提示,假设它始终使用您可以查找的某些字符串。 Alternatively, if the subprocess is expected to generate output continually then you could simply look for any output and if a configured amount of time goes past without any output then you declare that process dead and terminate it as detailed above. 或者,如果期望子进程连续产生输出,则可以简单地寻找任何输出,并且如果经过配置的时间量没有任何输出,则可以声明该进程死机并终止它,如上所述。

Since you're reading the output, actually you don't need poll() or wait() - the process closing its output file descriptor is good enough to know that it's terminated in this case. 由于您正在读取输出,因此实际上您不需要poll()wait() -关闭其输出文件描述符的进程足以知道在这种情况下它已终止。

Here's an example of a modified run_use() method which watches the output of the subprocess: 这是修改后的run_use()方法的示例,该方法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

In this example we assume that the process either gets hung on on UserPrompt>>> (replace with the appropriate string) or it terminates naturally. 在此示例中,我们假定该进程要么挂在UserPrompt>>> (用适当的字符串替换)上, 要么自然终止。 If it were to get stuck in an infinite loop, for example, then your script would still not terminate - you can only really address that with an overall timeout, but you didn't seem keen to do that. 例如,如果它陷入无限循环,那么脚本仍然不会终止-您只能在整体超时的情况下真正解决该问题,但您似乎并不热衷于此。 Hopefully your subprocess won't misbehave in that way, however. 希望您的子流程不会那样做。

Finally, if you don't know in advance the prompt that will be giving from your process then your job is rather harder. 最后,如果您事先不知道过程中将给出的提示,那么您的工作就很难了。 Effectively what you're asking to do is monitor an external process and know when it's blocked reading on a file descriptor, and I don't believe there's a particularly clean solution to this. 实际上,您要执行的操作是监视外部进程,并知道何时阻止对文件描述符的读取,而且我认为没有特别干净的解决方案。 You could consider running a process under strace or similar, but that's quite an awful hack and I really wouldn't recommend it. 可以考虑在strace或类似条件下运行一个进程,但这是一个非常糟糕的黑客,我真的不建议这样做。 Things like strace are great for manual diagnostics, but they really shouldn't be part of a production setup. 诸如strace之类的东西对于手动诊断非常有用,但是它们实际上不应该成为生产设置的一部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM