wxPython使用delayedresult进行耗时计算

wxPython使用delayedresult进行耗时计算[python GUI教程]

delayedresult使用背景介绍

在进行wxPython GUI画面编程时,如直接在画面主线程进行大量耗时计算处理,就会造成画面假死,不能响应用户输入。

使用wxPython的delayedresult模块,可轻松解决该问题,甚至都不需要了解相关线程处理机制,即可方便的把耗时处理放到单独的线程中,处理结束后把结果返回GUI画面主线程,并调用预先定义的相关处理,进行画面更新等。

为了演示delayedresult的使用情况,先新建一TestWindow框架,doSomeThing()是我们模拟进行大量耗时处理的函数。

import wx
 from wx.lib.delayedresult import startWorker
 import threading
  
 class TestWindow(wx.Frame):
     def __init__(self, title="Test Window"):
         self.app = wx.App(False)
         wx.Frame.__init__(self, None, -1, title)
         panel = wx.Panel(self)
         self.btnBegin = wx.Button(panel, -1, label="Begin")
         self.Bind(wx.EVT_BUTTON, self.handleButton, self.btnBegin)
         self.txtCtrl = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(300, -1))
         vsizer = wx.BoxSizer(wx.VERTICAL)
         vsizer.Add(self.btnBegin, 0, wx.ALL, 5)
         vsizer.Add(self.txtCtrl, 0, wx.ALL, 5)
         panel.SetSizer(vsizer)
         vsizer.SetSizeHints(self)
         self.Show()
  
     #处理Begin按钮事件
     def handleButton(self, event):
         self.workFunction()
  
     #开始执行耗时处理,有继承类实现
     def workFunction(self, *args, **kwargs):
         print"In workFunction(), Thread=", threading.currentThread().name
         print "	*args:", args
         print "	**kwargs:", kwargs
          
         self.btnBegin.Enable(False)
  
     #耗时处理处理完成后,调用该函数执行画面更新显示,由继承类实现
     def consumer(self, delayedResult, *args, **kwargs):
         print "In consumer(), Thread=", threading.currentThread().name
         print "	delayedResult:", delayedResult
         print "	*args:", args
         print "	**kwargs:", kwargs
  
         self.btnBegin.Enable(True)
  
     #模拟进行耗时处理并返回处理结果,给继承类使用
     def doSomeThing(self, *args, **kwargs):
         print"In doSomeThing(), Thread=", threading.currentThread().name
         print "	*args:", args
         print "	**kwargs:", kwargs
          
         count = 0
         while count < 10**8:
             count += 1
              
         return count

先看看如在GUI画面主线程进行doSomeThing()处理的

class DoSomeThingInGUI(TestWindow):
     def __init__(self):
         TestWindow.__init__(self, "Do Something In GUI Thread")
         self.app.MainLoop()
  
     #执行doSomeThing(),并在执行完成后,主动调用consumer()更新画面显示
     def workFunction(self, *args, **kwargs):
         TestWindow.workFunction(self, args, kwargs)
         var = self.doSomeThing()
         self.consumer(var)
  
     def consumer(self, delayedResult, *args, **kwargs):
         TestWindow.consumer(self, delayedResult, args, kwargs)
         self.txtCtrl.SetValue(str(delayedResult))
          
 if __name__ == "__main__":
     win = DoSomeThingInGUI()

执行后,点Begin开始后,直到处理完成画面窗口无法移动。

由以下log输出可以知道,处理都是在GUI画面主线程中完成的。

In workFunction(), Thread= MainThread

*args: ((), {})

**kwargs: {}

In doSomeThing(), Thread= MainThread

*args: ()

**kwargs: {}

In consumer(), Thread= MainThread

delayedResult: 100000000

*args: ((), {})

**kwargs: {}

使用wx.lib.delayedresult后的处理情况:

class DoSomeThingInSeperateThread(TestWindow):
     def __init__(self):
         TestWindow.__init__(self, "Do Something In Seperate Thread")
         self.jobId = 100
         self.app.MainLoop()
  
     #调用wx.lib.delayedresult.startWorker,把函数处理放到单独的线程中去完成。
     #完成后会自动调用consumer进行画面更新处理
     #startWorker函数的各参数接下来分析
     def workFunction(self, *args, **kwargs):
         TestWindow.workFunction(self, args, kwargs)
         startWorker(self.consumer, self.doSomeThing, jobID=self.jobId)
  
     #第一参数要为DelayedResult类型,即包含处理结果或异常信息,调用get接口取得。
     def consumer(self, delayedResult, *args, **kwargs):
         TestWindow.consumer(self, delayedResult, args, kwargs)
         assert(self.jobId == delayedResult.getJobID())
         try:
             var = delayedResult.get()
         except Exception, e:
             print "Result for job %s raised exception:%s" %(delayedResult.getJobID, e)
                  
         self.txtCtrl.SetValue(str(var))
          
 if __name__ == "__main__":
     win = DoSomeThingInSeperateThread()

执行后,点Begin开始后,窗口移动不受影响,也就是说处理是异步的。

由以下log输出可以知道,耗时处理doSomeThing是在独立线程运行的。

处理完成后的画面更新处理consumer还是在GUI画面主线程完成的。

In workFunction(), Thread= MainThread

*args: ((), {})

**kwargs: {}

In doSomeThing(), Thread= 100

*args: ()

**kwargs: {}

In consumer(), Thread= MainThread

delayedResult: <wx.lib.delayedresult.DelayedResult instance at 0x02FFE828>

*args: ((), {})

**kwargs: {}

来源:PY学习网:原文地址:https://www.py.cn/article.html

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » wxPython使用delayedresult进行耗时计算