python - 使用 Python 子进程处理交互式 shell

标签 python python-2.7 shell subprocess python-multiprocessing

我正在尝试使用多处理池运行基于控制台的游戏(地牢爬行石头汤——自然用于研究目的)的多个实例来评估每次运行。

过去,当我使用池来评估类似代码(遗传算法)时,我使用 subprocess.call 来拆分每个进程。然而,由于 dcss 具有相当大的交互性,因此共享子 shell 似乎是有问题的。

我有我通常用于此类事情的代码,用爬网替换我已经投入 GA 的其他应用程序。有没有比这更好的方法来处理高度交互的 shell?我考虑过为每个实例启动一个屏幕,但认为有更简洁的方法。我的理解是 shell=True 应该产生一个子 shell,但我想我是在以每次调用之间共享的方式产生一个子 shell。

我应该提到我有一个运行游戏的机器人,所以我不希望发生任何来自用户端的实际交互。

# Kick off the GA execution
pool_args = zip(trial_ids,run_types,self.__population)
pool.map(self._GAExecute, pool_args)

---

# called by pool.map 
def _GAExecute(self,pool_args):
  trial_id       = pool_args[0]
  run_type       = pool_args[1]
  genome         = pool_args[2]
  self._RunSimulation(trial_id)

# Call the actual binary
def _RunSimulation(self, trial_id):
  command = "./%s" % self.__crawl_binary
  name    = "-name %s" % trial_id
  rc      = "-rc %s" % os.path.join(self.__output_dir,'qw-%s'%trial_id,"qw -%s.rc"%trial_id)
  seed    = "-seed %d" % self.__seed
  cdir    = "-dir %s" % os.path.join(self.__output_dir,'qw-%s'%trial_id)

  shell_command = "%s %s %s %s %s" % (command,name,rc,seed,cdir)
  call(shell_command, shell=True)

最佳答案

您确实可以将 stdin 和 stdout 关联到文件,如@napuzba 的回答:

fout = open('stdout.txt','w')
ferr = open('stderr.txt','w')
subprocess.call(cmd, stdout=fout, stderr=ferr)

另一种选择是使用 Popen而不是 call .不同之处在于 call 等待完成(阻塞)而 Popen 不是,参见 What's the difference between subprocess Popen and call (how can I use them)?

使用 Popen,您可以将 stdout 和 stderr 保留在对象中,然后在以后使用它们,而不必依赖文件:

p = subprocess.Popen(cmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.wait()
stderr = p.stderr.read()
stdout = p.stdout.read()

此方法的另一个潜在优势是您可以运行多个 Popen 实例而无需等待完成而不是使用线程池:

processes=[
  subprocess.Popen(cmd1,stdout=subprocess.PIPE, stderr=subprocess.PIPE),
  subprocess.Popen(cmd2,stdout=subprocess.PIPE, stderr=subprocess.PIPE),
  subprocess.Popen(cmd3,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
]

for p in processes:
  if p.poll():
     # process completed
  else:
     # no completion yet

附带说明,您应该 avoid shell=True 如果你可以,如果你不使用它 Popen 期望列表作为命令而不是字符串。不要手动生成此列表,而是使用 shlex它将为您处理所有极端情况,例如:

Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)

关于python - 使用 Python 子进程处理交互式 shell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43554548/

相关文章:

Python I/O 读取和追加(写入)

python - 循环遍历一个列表并将项目附加到一组三个列表中,一个接一个

python - __str__ 返回 UnicodeEncodeError,但在其他方面有效 (u'\xa0')

python - 在 Python 中使用 g++ 和子进程

python - 在 sqlalchemy 中强制对象为 `dirty`

python - 在 Python 2.7 中将 ½ 解析为 0.5

python - 将 JSON 值添加到列表中

linux - Ubuntu:在启动时使用 args 启动 shell 脚本

shell - 管道中变量的范围

shell - 是否可以在命令行中指定 shell 动词?