如何处理Python中并行运行的子进程的用户输入?

时间:2018-04-16 12:55:17

标签: python multithreading python-3.x parallel-processing popen

我有一个Python辅助函数来并行运行grunt命令,使用Popen来处理子进程。目的是通过CLI进行通信。当所有这些进程需要任何用户输入时,例如,问题就开始了。文件路径,密码,'是/否'决定:

Enter file path: Enter file path: Enter file path: Enter file path: Enter file path: Enter file path: Enter file path: 
Everything up-to-date
Grunt task completed successfully.

用户提供一次输入,一个进程成功完成,其他所有进程都没有完成执行。

代码:

from subprocess import check_output, Popen

def run_grunt_parallel(grunt_commands):

    return_code = 0

    commands = []
    for command in grunt_commands:
        with tempfile.NamedTemporaryFile(delete=False) as f:
            app = get_grunt_application_name(' '.join(command))
            commands.append({'app': app, 'process': Popen(command, stdout=f)})

    while len(commands):
        sleep(5)
        next_round = []
        for command in commands:
            rc = command['process'].poll()
            if rc == None:
                next_round.append(command)
            else:
                if rc == 0:
                else:
                    return_code = rc

        commands = next_round

    return return_code

有没有办法确保用户可以为每个流程提供所有必要的输入?

1 个答案:

答案 0 :(得分:0)

你想要的只是几乎(如果不是完全)不可能。但是,如果您能够以无前缀的方式识别提示(并且,如果它有所不同,从中了解他们期望的输入线数),您应该能够管理它。

使用双向无缓冲管道运行每个进程:

Popen(command, stdin=subprocess.PIPE,
      stdout=f, stderr=subprocess.PIPE, bufsize=0)

(表现良好的程序会出现标准错误。您似乎这样做了,因为尽管stdout=f显示了提示,但是如果它们不能可靠地显示提示,您可以从管道读取好吧,在其中搜索提示,并自己将其复制到文件中。)

的Unix

将所有管道设置为非阻塞。然后使用select监视所有进程的stderr管道。 (您可以尝试使用selectors。)缓冲为每个进程单独阅读的内容,直到您从一个进程中识别出提示。然后显示提示(标识源进程)并接受来自用户的输入 - 如果提示之间的输出适合管道缓冲区,这不会减慢后台工作速度。将该用户输入放在与该进程关联的缓冲区中,并将其stdin管道添加到select

stdin管道显示准备就绪时,请写入,并在完成此操作后将其从集合中删除。当从管道读取时返回EOF,join相应的进程(如果您担心某个进程可能提前关闭它,则在SIGCHLD处理程序中执行此操作)。

除非您有可用的select仿真支持管道,否则您必须为每个进程使用一个线程,或者如果一个进程在写入提示后可能产生输出并且在读取之前,则必须使用每个进程一个响应。然后使用Queue将提示作为消息发布到主线程,然后可以使用(例如)另一个进程Queue将用户输入发送回线程(或其写作伙伴)

这适用于任何threading - 支持平台,并且具有不依赖管道缓冲区以避免拖延健谈过程的潜在优势。