6

这与我关于 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 交互。但是应该如何使用pexpect,尤其是考虑到后台进程是长期的、独立运行的任务?

例如,如果我使用

child=pexpect.spawn(launchcmd)

如何获取子进程的输出和输入,这样我就可以使用 wx.TextCtrl 打印输出,也可以使用 wx.TextCtrl 将用户输入转发到子进程?

4

2 回答 2

13

您是否尝试过类似的方法:

child = pexpect.spawn(launchcmd)
while True:
    try:
        child.expect('\n')
        print(child.before)
    except pexpect.EOF:
        break
于 2010-11-17T21:22:16.150 回答
2

我发现这两种方法可以很好地获取实时输出。

如果您不想要用户交互选项,例如在后台进程中:

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()    
于 2014-06-11T16:41:03.627 回答