为何我的SSH子进程串行运行而非并行执行?
问题:SSH进程未并行执行的原因及修复
我的脚本包含两个循环:
- 第一个循环为每台远程机器启动多个
ssh进程; - 第二个循环收集并打印每个进程的stderr、stdout,并检查其
returncode
通过各进程中date命令的输出可确认,所有进程均为串行运行,但我预期它们能并行执行。请问我哪里操作有误?
import os import locale import subprocess import logging logging.basicConfig(level=logging.INFO) Nodes = ["node1", "node2", "localhost"] # 示例节点列表 pipes = {} myhostname = os.uname()[1].lower() for node in Nodes: if node.lower() == myhostname: cmd = '/bin/bash' else: cmd = ('ssh -q ' '-o PasswordAuthentication=no ' '-o StrictHostKeyChecking=no ' '%s /bin/bash') % node pipe = subprocess.Popen(cmd.split(' '), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True, encoding = locale.getlocale()[1]) pipe.stdin.write(""" date sleep 1 date exit""") pipes[node] = pipe logging.info('%d processes spawn, collecting outputs', len(pipes)) errCount = 0 for (node, pipe) in pipes.items(): out, err = pipe.communicate() if err: logging.warn('%s stderr: %s', node, err.strip()) if out: logging.info('%s stdout: %s', node, out.strip()) if pipe.returncode != 0: errCount += 1 logging.error('Got exit code %d from %s, increasing ' 'error-count to %d', pipe.returncode, node, errCount)
错误原因
核心问题是向子进程标准输入写入命令后,未关闭stdin。
远程的bash进程收到你写入的命令后,会一直等待更多输入(因为stdin处于打开状态),不会立即执行脚本内容。直到第二个循环调用pipe.communicate()时,该方法才会隐式关闭子进程stdin,此时bash才开始执行命令。而communicate()本身是阻塞调用,会等待当前子进程执行完毕再处理下一个,最终导致所有进程串行运行。
修复方案
在第一个循环中,写完stdin后立即关闭它,让bash进程收到EOF并开始执行命令,这样所有子进程就能并行运行。
修改第一个循环的代码,在pipe.stdin.write(...)后添加pipe.stdin.close():
pipe.stdin.write(""" date sleep 1 date exit""") pipe.stdin.close() # 添加这一行,关闭标准输入 pipes[node] = pipe
额外优化建议
- 可以用
subprocess.Popen配合communicate(input=...)传递命令,这样更简洁,也能避免手动管理stdin的问题,但注意不要在第一个循环中直接调用communicate()(会导致串行),仍需先启动所有进程再统一收集结果。 - 针对大量节点场景,可使用
concurrent.futures等并发库管理进程,代码会更简洁易维护。
内容的提问来源于stack exchange,提问作者Mikhail T.
相关产品推荐
相关产品推荐

