【问题标题】:Python Subprocess: replicating Tee with subprocess.Popen and executing in parallel?Python Subprocess:使用 subprocess.Popen 复制 Tee 并并行执行?
【发布时间】:2014-12-24 15:24:15
【问题描述】:

我正在尝试编写一个 python 脚本来编译并通过 Arduino 的命令行界面将相同的 hex 文件并行上传到多个微控制器。

我的脚本执行以下操作:

  1. 将 ino 文件编译为特定目录中的 hex 文件。例如,
  2. 将十六进制上传到所有 /dev/tty.usbXXXXXX。

这些是要求:

  • 我必须能够并行上传到多个 /dev/tty.usb*。
  • 我想打印所有子进程中的所有 stdout 和 stderr。以 DEVICE - STDOUT/STDERR - MSG 作为格式打开到我的主屏幕
  • 我想将每个 Popen 中的 stdout 和 stderr 都保存到其自己的 tty.usb* 日志文件中。

现在我有:

import errno
import os
import re
import subprocess

ARDUINO_EXECUTABLE = '/Applications/Arduino.app/Contents/MacOS/JavaApplicationStub'
HEX_FOLDER_DIR = '/tmp/oyoroi'
LOG_FOLDER_DIR = './logs'


def get_devices():
  """Returns a list of tty.usbXXXXXX
  Make sure you use the USB hub. This will force an extra character in the /dev/tty.usbXXXXXX
  """
  ret = []
  for device in os.listdir('/dev'):
    if re.match('tty.usbmodem[0-9]{6}', device):
      ret.append(device)
  return ret


class Wrapper(object):
  """Wrapper for file objects
  """
  def __init__(self, name, fobject):
    self.name = name
    self.fobject = fobject

  def fileno(self):
    return self.fobject.fileno()

  def flush(self):
    self.fobject.flush()

  def write(self, a_str):
    print self.name, a_str
    self.fobject.write(a_str)


def main(fname):
  """Build once, but upload in parallel
  """
  try:
    os.makedirs(HEX_FOLDER_DIR)
  except OSError as exc:
    if exc.errno == errno.EEXIST and os.path.isdir(HEX_FOLDER_DIR):
      pass

  fname = os.path.abspath(fname)

  # Builds the hex
  command = "%s --verify --pref build.path=%s %s" % (ARDUINO_EXECUTABLE, HEX_FOLDER_DIR, fname)
  print "(Build Command)", command
  proc = subprocess.call(command, shell=True)

  # Make the log directory
  try:
    os.makedirs(LOG_FOLDER_DIR)
  except OSError as exc:
    if exc.errno == errno.EEXIST and os.path.isdir(LOG_FOLDER_DIR):
      # delete folder
      import shutil
      shutil.rmtree(LOG_FOLDER_DIR)
      # and recreate again
      os.makedirs(LOG_FOLDER_DIR)

  # Upload in parallel
  devices = get_devices()
  processes = []

  for device in devices:
    device_path = '/dev/' + device
    log_file_path = os.path.join(LOG_FOLDER_DIR, device + '.log')
    with open(log_file_path, 'a') as logfile:
      command = "%s --upload --pref build.path=%s --port %s %s" % \
                (ARDUINO_EXECUTABLE, HEX_FOLDER_DIR, device_path, fname)
      print "(Upload Command)", command

      wstdout = Wrapper('%_STDOUT', logfile)
      wstderr = Wrapper('%_STDERR', logfile)
      proc = subprocess.Popen(command, shell=True, stdout=wstdout, stderr=wstderr)
      processes.append(proc)


if __name__ == "__main__":
  import sys
  if len(sys.argv) != 2:
    print "python upload.py <.ino>"
    exit(1)
  main(sys.argv[1])

我能够在每个日志文件中获得我想要的内容,但我的终端没有在屏幕上打印任何内容。它也在其他过程完成之前结束。

我错过了什么?

【问题讨论】:

标签: python arduino pipe subprocess


【解决方案1】:

main() 的末尾,添加如下代码:

for proc in processes:
    proc.wait()

现在,您无需等待,因此 Python 会在所有进程启动后立即退出。

为了记录,我不完全确定传递 Wrapper 对象而不是真正的文件对象有多大用处。 Python 很可能只是调用.fileno(),然后直接将子进程附加到该文件描述符。您的 .write() 方法可能没有被调用。如果您需要调用它,您应该使用subprocess.PIPEPopen.communicate() 代替Wrapper 对象和Popen.wait()。然后,您可以以任何您认为合适的方式使用 communicate() 的返回值(即打印它)。

【讨论】:

  • 所以我尝试做这样的事情:gist.github.com/vicngtor/40d9cb41780a0d5f14e8 最后没有打印出来。我错过了什么吗?
  • communicate() 仅在您将subprocess.PIPE 作为stdout 和/或stderr 传递时才有效(然后仅适用于您传递的流)。在这种情况下,我相信您需要手动将write() 写入日志文件并将print() 写入屏幕,使用communicate() 返回值。
猜你喜欢
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-01
  • 1970-01-01
  • 2020-02-14
  • 2014-01-15
  • 1970-01-01
相关资源
最近更新 更多