WxPython在循环中创建NewEvent会导致GUI速度变慢

时间:2017-06-22 19:34:51

标签: wxpython wxwidgets

我有一个运行的线程监视事物的状态,并发布事件以刷新Gui,最大速率为0.1秒。然而,几个小时后我注意到Gui变得迟钝,最终会冻结。

class Hello(wx.Frame):

    def __init__(self):
        self.refreshEvent, EVT_REFRESH_GUI = wx.lib.newevent.NewEvent()
        self.Bind(EVT_REFRESH_GUI, self.__RefreshGui)

    def MyThread(self):

        while(True):
            # Do stuff
            self.var = self.GetVar()

            # Post refresh event.
            refreshEvent = self.refreshEvent()
            wx.PostEvent(self, refreshEvent)
            time.sleep(0.1)

    def __RefreshGui(self, event):
        pass

我刚刚意识到,如果我将refreshEvent = self.refreshEvent()移到while循环之外,那么所有内容似乎都更具响应性。

我还没有看到任何关于创造导致滞后的新事件的事情。这是一个已知和预期的行为吗?这是因为wxPython,还是来自wxWidgets?

class Hello(wx.Frame):

    def __init__(self):
        self.refreshEvent, EVT_REFRESH_GUI = wx.lib.newevent.NewEvent()
        self.Bind(EVT_REFRESH_GUI, self.__RefreshGui)

    def MyThread(self):
        refreshEvent = self.refreshEvent()
        while(True):
            # Do stuff
            self.var = self.GetVar()

            # Post refresh event.
            wx.PostEvent(self, refreshEvent)
            time.sleep(0.1)

    def __RefreshGui(self, event):
        pass

编辑:

要解决一些当前的评论和答案,这是真实代码的简化视图,以尝试并专注于导致我的问题的原因。是的,代码中有一个真正的线程。我们可以尝试为未来采用wxTimer方法,我很感激反馈,因为我想知道如何最好地解决这个问题。我们使用PostEvent的原因是因为我们需要它是线程安全的。以前我们遇到了来自不同线程调用相同内容的段错误问题。有大量遗留代码,这在当时似乎是一种很好的方法。

这个问题真的很奇怪是否存在创建和发布自定义事件数量的固有减速。创建事件和发布事件的方法是多次,预计会导致放缓?

2 个答案:

答案 0 :(得分:1)

仅仅因为你调用类方法MyThread并不会自动使它成为一个线程。但在某种程度上,你已经走上正轨。

您需要查看主题LongRunningTasks on the wxPython wiki,尤其是页面底部的最简单的实施 Ever :)部分。

您的GUI冻结是因为sleep在无休止的while循环中占用了所有资源。这可以保证wxPython不再能够对任何事件做出反应(也是你自己创建的事件)。

我的建议:首先,摆脱你的自定义事件。你不需要这个。

你基本上有两个选择:

  1. sleep移动到一个单独的线程中,并以线程安全的方式与主GUI线程通信(例如wx.CallBack)。这在wiki链接中有很好的描述。

  2. 如果您只需要一些每100毫秒运行一次的代码,请使用wx.Timer(有关示例,请参阅wxPython演示)。但是,您必须确保您的工作可以在100毫秒以下完成,否则事件将会堆积。如果这是一个问题,请改用方法1。

答案 1 :(得分:0)

不重复别人的说法,虽然我同意,但这里有一个简单的wx.timer例子:

import wx
class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, -1, title,size=(350, 225))
        panel = wx.Panel(self)
        self.Text = wx.StaticText(panel,-1,"Tick")
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onTimer, self.timer)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.Text, 0, wx.ALL, 10)
        panel.SetSizer(sizer)
        self.timer.Start(2000) # fire every 2 seconds
        self.Show()

    def onTimer(self, evt):
        if self.Text.GetLabel() == "Tick":
            self.Text.SetLabel("Tock")
        else:
            self.Text.SetLabel("Tick")

if __name__ == '__main__':
    app = wx.App()
    MyFrame(None,"Tick Tock timer")
    app.MainLoop()