wxPython使用delayedresult進行耗時計算

pythontab發表於2013-01-02

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 '\t*args:', args
         print '\t**kwargs:', kwargs
          
         self.btnBegin.Enable(False)
  
     #耗時處理處理完成後,呼叫該函式執行畫面更新顯示,由繼承類實現
     def consumer(self, delayedResult, *args, **kwargs):
         print 'In consumer(), Thread=', threading.currentThread().name
         print '\tdelayedResult:', delayedResult
         print '\t*args:', args
         print '\t**kwargs:', kwargs
  
         self.btnBegin.Enable(True)
  
     #模擬進行耗時處理並返回處理結果,給繼承類使用
     def doSomeThing(self, *args, **kwargs):
         print'In doSomeThing(), Thread=', threading.currentThread().name
         print '\t*args:', args
         print '\t**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: {}




相關文章