Reputation: 3087
I have a thread running which monitors the state of things, and posts an event to refresh the Gui with a max rate of 0.1s. However, I noticed after several hours that the Gui became sluggish and would eventually freeze.
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
I just realized that if I move refreshEvent = self.refreshEvent()
outside the while loop everything seems much more responsive.
I haven't seen anything about creating new events causing lag. Is this a known and expected behavior? Is this specifically because of wxPython, or is this from 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
EDIT:
To address some of the current comments and answers, this is a simplified view of the real code to try and focus on what was causing my issue. Yes, there is a real thread in the code. We can try to move towards a wxTimer
approach for the future, and I appreciate the feedback because I was wondering how to best go about this. The reason we are using PostEvent
is because we needed it to be thread safe. Previously we were running into segfault issues from different threads calling the same things. There is a significant amount of legacy code, and this seemed like a good approach at the time.
The question was really wondering if there was an inherent slowdown with the number of custom events created and posted. Is the approach of creating events and posting events many, many times expected to lead to a slowdown?
Upvotes: 0
Views: 304
Reputation: 22443
Without repeating what others have said, although I agree, here's a simple wx.timer
example:
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()
Upvotes: 0
Reputation: 3177
Just because you call a class method MyThread
does not automatically make it a Thread. But in some way you are already on the right track.
You will want to check out the topic LongRunningTasks on the wxPython wiki, especially the section Easiest Implementation Ever :) at the bottom of the page.
Your GUI freezes because you are eating up all resources by sleep
ing in an endless while
loop. This guarantees that wxPython will not be able to react to any Events any more (also the one you created yourself).
My advice: First, get rid of your custom event. You do not need that here.
You essentially have two options:
Moving the sleep
into a separate thread and communicate with the main GUI thread in thread-safe ways (e. g. wx.CallBack
). This is described very well in the wiki link.
If you just need some code which is run every 100 ms, use wx.Timer
(see the wxPython demo for an example). However, you have to make sure, that your work can be done in well than below 100 ms, otherwise events will pile up. If this is an concern, use Method 1 instead.
Upvotes: 1