[英]Redirecting processes from multiprocessing to separate wx.TextCtrl
我将使用多处理模块启动四个文本框和最多四个进程。 我可以让进程正常执行,但我真的想将每个进程的所有输出重定向到不同的wx.TextCtrl,这样我就可以看到整个解决方案过程中发生了什么。 我已成功完成了单个线程和sys.stdout重定向,如下所示
http://www.velocityreviews.com/forums/t515815-wxpython-redirect-the-stdout-to-a-textctrl.html
但类似的想法不适用于流程。 有人可以解决这个问题的简单解决方案吗? 我无法想象我是唯一一个遇到过这个问题的人。
据我了解,在wxPython中你通常想从一个线程运行进程。 所以你从进程到线程以及从线程回到wxPython。 我会使用某种命名方案将每个潜在的进程与文本控件(可能是1-4?)相关联,并将其传递给将使用wx.CallAfter或wx.PostEvent告诉wx更新的线程。
您也许可以使用简单的Python套接字服务器来完成此任务。 使用标题向服务器发布消息,该标题指出它属于哪个文本控件。 在wx部分,您可以使用wx.Timer检查套接字服务器是否有新消息,并根据需要进行更新。
对于那些感兴趣的人,这是一个有效的代码片段,可以完成我原来的问题。 它是一种享受。
此代码创建一个包装进程的线程。 在进程的run()函数中,使用重定向类将stderr和stdout重定向到管道。 可以对管道进行酸洗,这是在过程的run()函数中使用它们的先决条件。
只要有输出等待,线程就会坐下并从管道中拉出输出。 从管道中提取的文本使用wx.CallAfter函数写入wx.TextCtrl。 请注意,这是一个非阻塞调用,实际上这里的所有代码都是非阻塞的,这使得响应式GUI成为可能。 注意重定向类中的flush()函数也可以重定向stderr。
注意:有一点需要注意的是,如果您尝试使用过高吞吐量的管道进行读写操作,GUI将会锁定。 但只要你的输出速度相当慢,就没有问题
import wx
import sys
import time
from multiprocessing import Pipe, Process
from threading import Thread
class RedirectText2Pipe(object):
def __init__(self, pipe_inlet):
self.pipe_inlet = pipe_inlet
def write(self, string):
self.pipe_inlet.send(string)
def flush(self):
return None
class Run1(Process):
def __init__(self, pipe_inlet):
Process.__init__(self)
self.pipe_std = pipe_inlet
def run(self):
redir = RedirectText2Pipe(self.pipe_std)
sys.stdout = redir
sys.stderr = redir
for i in range(100):
time.sleep(0.01)
print i,'Hi'
class RedirectedWorkerThread(Thread):
"""Worker Thread Class."""
def __init__(self, stdout_target):
"""Init Worker Thread Class."""
Thread.__init__(self)
self.stdout_target_ = stdout_target
def run(self):
"""
In this function, actually run the process and pull any output from the
pipes while the process runs
"""
pipe_outlet, pipe_inlet = Pipe(duplex = False)
p = Run1(pipe_inlet)
p.daemon = True
p.start()
while p.is_alive():
#Collect all display output from process
while pipe_outlet.poll():
wx.CallAfter(self.stdout_target_.WriteText, pipe_outlet.recv())
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None)
self.txt1 = wx.TextCtrl(self, style = wx.TE_MULTILINE|wx.TE_READONLY)
self.txt2 = wx.TextCtrl(self, style = wx.TE_MULTILINE|wx.TE_READONLY)
self.txt3 = wx.TextCtrl(self, style = wx.TE_MULTILINE|wx.TE_READONLY)
self.btn = wx.Button(self, label='Run')
self.btn.Bind(wx.EVT_BUTTON, self.OnStart)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.AddMany([(self.txt1,1,wx.EXPAND),(self.txt2,1,wx.EXPAND),(self.txt3,1,wx.EXPAND),self.btn])
self.SetSizer(sizer)
def OnStart(self, event):
t1 = RedirectedWorkerThread(self.txt1)
t1.daemon = True
t1.start()
t2 = RedirectedWorkerThread(self.txt2)
t2.daemon = True
t2.start()
t3 = RedirectedWorkerThread(self.txt3)
t3.daemon = True
t3.start()
if __name__ == '__main__':
app = wx.App(False)
frame = MainFrame()
frame.Show(True)
app.MainLoop()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.