这与我使用wx.TextCtrl(或底层GTK +)发布的另一个多线程问题有关,在通过从主线程调用GUI交互进行更正后,我发现它再次涉及到管道块缓冲问题。那么如何从subprocess.stdout获得自发输出呢?
简而言之,当前我正在使用subprocess.popen启动外部长期运行的程序。
launchcmd=["EXTERNAL_PROGRAM_EXE"]
p = subprocess.Popen(launchcmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.outputThread = BashProcessThread(p.stdout.readline)
self.outputThread.start()
# wx.TextCtrl is used to make input/output
self.textctrl = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER|wx.TE_MULTILINE)
我使用一个单独的线程读取后台程序的标准输出,并使用" wx.CallAfter"进行回调。
class BashProcessThread(threading.Thread):
def __init__(self, readlineFunc, textctrl):
threading.Thread.__init__(self)
self.readlineFunc = readlineFunc
def run(self):
while True:
line = self.readlineFunc()
wx.CallAfter(textctrl.AppendText(line))
上面的代码打印出子进程日志消息的块挂起的块(而不是自发地一行一行),最糟糕的是直到用户发送下一个输入之前,其余5-6行的日志消息才被及时打印。
从我的旧文章中,我知道有pty和pexpect,这可能使子流程认为它正在与伪tty交互。但是应该如何使用预期,特别是考虑到后台进程是长期的,独立运行的任务呢?
例如,如果我使用
child=pexpect.spawn(launchcmd)
如何获得子流程的输出和输入,因此我可以使用wx.TextCtrl打印输出,还可以使用wx.TextCtrl将用户输入转发到子流程?
您是否尝试过类似的方法:
child = pexpect.spawn(launchcmd)
while True:
try:
child.expect('
')
print(child.before)
except pexpect.EOF:
break
我花了30分钟的时间尝试生成所有的读取命令。 甚至从未见过before属性。 祝您一切顺利。
我认为更优雅的解决方案是使用child.logfile属性。
我发现这两种方法都能很好地获得实时输出。
如果您不希望用户进行交互,例如在后台流程中:
child = pexpect.spawn(launchcmd)
child.logfile = sys.stdout
child.expect(pexpect.EOF)
child.close()
如果您不使用后台进程,并且希望能够与该程序进行交互(如果它提示您)。 在这里发生的是,您进入了交互模式,并且pexpect直接写入屏幕。 程序运行结束/ EOF时,将引发OSError。
child = pexpect.spawn(launchcmd)
try:
child.interact()
except OSError:
pass
child.close()