尝试使用subprocess.Popen
在单独的线程中创建运行某些bash作业(用于闪存)的python脚本。在运行时我想读取进程的标准输出,这样我就可以在一个简单的curses界面中向用户显示一些进度。所以每个线程运行如下:
def worker(panel):
panel['status'] = 'STARTING'
panel['process'] = Popen([SCRIPTFILE, panel['ip'], FWFILE, JADFILE, EXEFILE], stdout=PIPE, bufsize=1048576)
panel['status'] = 'RUNNING'
line = " "
while line:
line = panel['process'].stdout.readline()
panel['status'] = line
panel['status'] = 'DONE'
我在我的UI中看到状态在这种情况下卡在STARTING
上,但是看着IP流量,它似乎实际上运行但从不返回任何输出。所以看来Popen
实际上是在运行这个工作但是没有返回。一旦其他进程完成,它似乎停止挂起,我得到所有数据,因为它被缓冲。我已经看到有关从子进程读取stdout的警告,但这些警告似乎与其他方案有关。我不能真正使用communicate()
,因为它等待过程完成。知道什么可以使Popen
像这样挂起来吗?
试图在这里制作一个显示问题的最小版本(在Linux上运行python 2.7(如果是windows,则在脚本中更改查找路径)):
import curses
import time
from subprocess import *
import threading
def check_done(panels):
done = True
for panel in panels:
if panel['status'] != 'DONE':
done = False
break
return done
def flash_worker(panel):
panel['status'] = 'STARTING'
panel['process'] = Popen(["find", "/usr"], stdout=PIPE, bufsize=1048576)
panel['status'] = 'RUNNING'
line = " "
while line:
line = panel['process'].stdout.readline()
panel['status'] = line
panel['status'] = 'DONE'
def ui_worker(panels):
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.keypad(1)
stdscr.scrollok(1)
stdscr.erase()
stdscr.refresh()
while not check_done(panels):
y = 0
stdscr.clear()
stdscr.addstr(y, 0, "IP")
stdscr.addstr(y, 15, "Status")
height, width = stdscr.getmaxyx()
for i in range(0, len(panels)):
y = y + 1
stdscr.addstr(y, 0, "%s" % (panels[i]['ip']))
stdscr.addstr(y, 15, "%s" % (panels[i]['status']))
stdscr.refresh()
time.sleep(0.1)
curses.nocbreak();
stdscr.keypad(0);
curses.echo()
curses.endwin()
def main():
panels = []
for i in range(0,25):
panels.append({ 'ip' : '192.168.0.%d' % (i), 'mac' : '', 'status' : '', 'thread' : None, 'success' : False })
for panel in panels:
panel['thread'] = threading.Thread(name='Panel %s' % (panel['ip']), target = flash_worker, args = (panel,))
panel['thread'].start()
try:
ui_worker(panels)
except KeyboardInterrupt:
print "Caught KeyboardInterrupt, terminating..."
for panel in panels:
panel['thread'].join()
if __name__ == "__main__":
main()
答案 0 :(得分:0)
找到一个解决方案,而不是100%确定它的工作原理。但是,在分叉(使用Popen)时设置 close_fds = True 可以解决问题。