代码之家  ›  专栏  ›  技术社区  ›  Achimnol

更好地多线程使用Python subprocess.Popen&communicate()?

  •  3
  • Achimnol  · 技术社区  · 14 年前

    我在运行Python 2.6的Linux机器上运行多个命令,这可能需要一些时间。

    所以,我用 subprocess.Popen 类和 process.communicate() 方法并行执行多个命令组,并在执行后立即捕获输出。

    def run_commands(commands, print_lock):
        # this part runs in parallel.
        outputs = []
        for command in commands:
            proc = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
            output, unused_err = proc.communicate()  # buffers the output
            retcode = proc.poll()                    # ensures subprocess termination
            outputs.append(output)
        with print_lock: # print them at once (synchronized)
            for output in outputs:
                for line in output.splitlines():
                    print(line)
    

    在其他地方,它的名字是这样的:

    processes = []
    print_lock = Lock()
    for ...:
        commands = ...  # a group of commands is generated, which takes some time.
        processes.append(Thread(target=run_commands, args=(commands, print_lock)))
        processes[-1].start()
    for p in processes: p.join()
    print('done.')
    

    预期的结果是,一组命令的每个输出在并行执行时同时显示。

    但是从第二个输出组(当然,成为第二个的线程由于调度的不确定性而改变)开始,它开始打印,没有换行符,并且添加的空格数与前一行中打印的字符数相同,并且输入回声被关闭——终端状态是“混乱”或“崩溃”。(如果我发布 reset shell命令,恢复正常。)

    起初,我试图从处理 '\r' ,但这不是原因。正如你在我的代码中看到的,我用 splitlines() ,我用 repr() 应用于输出的函数。

    我认为原因是 Popen communicate() 对于stdout/stderr。我试过了 check_output Python 2.7中的快捷方式方法,但没有成功。当然,如果我序列化所有命令执行和打印,则不会出现上述问题。

    有没有更好的办法 波本 通信() 同时?

    3 回复  |  直到 14 年前
        1
  •  2
  •   Achimnol    14 年前

    一个最终的结果灵感来自J.F.Sebastian的评论。

    http://bitbucket.org/daybreaker/kaist-cs443/src/247f9ecf3cee/tools/manage.py

    这似乎是一个Python bug。

        2
  •  0
  •   Satwik    14 年前

    我不确定run_命令实际需要做什么,但它似乎只是对子进程进行轮询,忽略返回代码并继续循环。当您到达打印输出的部分时,您如何知道子流程已经完成?

        3
  •  0
  •   DevPlayer    14 年前

    在您的示例代码中,我注意到您使用了:

    for line in output.splitlines(): 
    

    部分解决 /右 “使用

    for line in output.splitlines(True): 
    

    会有帮助的。