首页 > 编程 > Python > 正文

分析Python编程时利用wxPython来支持多线程的方法

2020-02-23 00:35:33
字体:
来源:转载
供稿:网友

如果你经常使用python开发GUI程序的话,那么就知道,有时你需要很长时间来执行一个任务。当然,如果你使用命令行程序来做的话,你回非常惊讶。大部分情况下,这会堵塞GUI的事件循环,用户会看到程序卡死。如何才能避免这种情况呢?当然是利用线程或进程了!本文,我们将探索如何使用wxPython和theading模块来实现。

wxpython线程安全方法

wxPython中,有三个“线程安全”的函数。如果你在更新UI界面时,三个函数都不使用,那么你可能会遇到奇怪的问题。有时GUI也忙运行挺正常,有时却会无缘无故的崩溃。因此就需要这三个线程安全的函数:wx.PostEvent, wx.CallAfter和wx.CallLater。据Robin Dunn(wxPython作者)描述,wx.CallAfter使用了wx.PostEvent来给应用程序对象发生事件。应用程序会有个事件处理程序绑定到事件上,并在收到事件后,执行处理程序来做出反应。我认为wx.CallLater是在特定时间后调用了wx.CallAfter函数,已实现规定时间后发送事件。

Robin Dunn还指出Python全局解释锁 (GIL)也会避免多线程同时执行python字节码,这会限制程序使用CPU内核的数量。另外,他还说,“wxPython发布GIL是为了在调用wx API时,其他线程也可以运行”。换句话说,在多核机器上使用多线程,可能效果会不同。

总之,大概的意思是桑wx函数中,wx.CallLater是最抽象的线程安全函数, wx.CallAfter次之,wx.PostEvent是最低级的。下面的实例,演示了如何使用wx.CallAfter和wx.PostEvent函数来更新wxPython程序。

wxPython, Theading, wx.CallAfter and PubSub

wxPython邮件列表中,有些专家会告诉其他人使用wx.CallAfter,并利用PubSub实现wxPython应用程序与其他线程进行通讯,我也赞成。如下代码是具体实现:

import time import wx    from threading import Thread from wx.lib.pubsub import Publisher    ######################################################################## class TestThread(Thread):   """Test Worker Thread Class."""     #----------------------------------------------------------------------   def __init__(self):     """Init Worker Thread Class."""    Thread.__init__(self)     self.start()  # start the thread      #----------------------------------------------------------------------   def run(self):     """Run Worker Thread."""    # This is the code executing in the new thread.     for i in range(6):       time.sleep(10)       wx.CallAfter(self.postTime, i)     time.sleep(5)     wx.CallAfter(Publisher().sendMessage, "update", "Thread finished!")      #----------------------------------------------------------------------   def postTime(self, amt):     """    Send time to GUI    """    amtOfTime = (amt + 1) * 10    Publisher().sendMessage("update", amtOfTime)    ######################################################################## class MyForm(wx.Frame):      #----------------------------------------------------------------------   def __init__(self):     wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")        # Add a panel so it looks the correct on all platforms     panel = wx.Panel(self, wx.ID_ANY)     self.displayLbl = wx.StaticText(panel, label="Amount of time since thread started goes here")     self.btn = btn = wx.Button(panel, label="Start Thread")        btn.Bind(wx.EVT_BUTTON, self.onButton)        sizer = wx.BoxSizer(wx.VERTICAL)     sizer.Add(self.displayLbl, 0, wx.ALL|wx.CENTER, 5)     sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)     panel.SetSizer(sizer)        # create a pubsub receiver     Publisher().subscribe(self.updateDisplay, "update")      #----------------------------------------------------------------------   def onButton(self, event):     """    Runs the thread    """    TestThread()     self.displayLbl.SetLabel("Thread started!")     btn = event.GetEventObject()     btn.Disable()      #----------------------------------------------------------------------   def updateDisplay(self, msg):     """    Receives data from thread and updates the display    """    t = msg.data     if isinstance(t, int):       self.displayLbl.SetLabel("Time since thread started: %s seconds" % t)     else:       self.displayLbl.SetLabel("%s" % t)       self.btn.Enable()    #---------------------------------------------------------------------- # Run the program if __name__ == "__main__":   app = wx.PySimpleApp()   frame = MyForm().Show()   app.MainLoop()            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表