Python子进程:如何使用subprocess.Popen并行执行Tee?
我正在尝试写一个Python脚本,通过Arduino的命令行接口,同时将同一个hex文件编译并上传到多个微控制器上。
我的脚本做了以下几件事:
- 将ino文件编译成一个hex文件,放在特定的目录里。例如,
- 将这个hex文件上传到所有的/dev/tty.usbXXXXXX设备上。
这些是我的需求:
- 我需要能够同时上传到多个/dev/tty.usb*设备。
- 我想把所有子进程的标准输出和错误输出都打印到主屏幕上,格式是设备 - 标准输出/错误输出 - 消息。
- 我想把每个子进程的标准输出和错误输出分别保存到各自的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])
我能在每个日志文件中得到我想要的内容,但我的终端屏幕上什么也没打印出来。而且在其他进程完成之前,它就结束了。
我缺少了什么呢?
1 个回答
0
在你的 main()
函数的最后,添加类似下面的代码:
for proc in processes:
proc.wait()
现在,你的程序没有在等待,所以 Python 一启动所有进程就直接退出了。
顺便说一下,我不太确定用 Wrapper
对象代替真正的文件对象到底有多大用处。Python 很可能只是调用了 .fileno()
,然后直接把子进程连接到那个文件描述符上。你的 .write()
方法可能根本没有被调用。如果你希望它被调用,应该用 subprocess.PIPE
和 Popen.communicate()
来替代 Wrapper
对象和 Popen.wait()
。这样你就可以根据需要使用 communicate()
的返回值(比如打印出来)。