最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

分析Python編程時(shí)利用wxPython來(lái)支持多線程的方法

 更新時(shí)間:2015年04月07日 15:50:18   投稿:goldensun  
這篇文章主要介紹了Python編程時(shí)利用wxPython來(lái)支持多線程的方法,本文主要以開(kāi)發(fā)GUI程序時(shí)做線程通訊作為一個(gè)示例來(lái)講解,需要的朋友可以參考下

如果你經(jīng)常使用python開(kāi)發(fā)GUI程序的話,那么就知道,有時(shí)你需要很長(zhǎng)時(shí)間來(lái)執(zhí)行一個(gè)任務(wù)。當(dāng)然,如果你使用命令行程序來(lái)做的話,你回非常驚訝。大部分情況下,這會(huì)堵塞GUI的事件循環(huán),用戶(hù)會(huì)看到程序卡死。如何才能避免這種情況呢?當(dāng)然是利用線程或進(jìn)程了!本文,我們將探索如何使用wxPython和theading模塊來(lái)實(shí)現(xiàn)。

wxpython線程安全方法

wxPython中,有三個(gè)“線程安全”的函數(shù)。如果你在更新UI界面時(shí),三個(gè)函數(shù)都不使用,那么你可能會(huì)遇到奇怪的問(wèn)題。有時(shí)GUI也忙運(yùn)行挺正常,有時(shí)卻會(huì)無(wú)緣無(wú)故的崩潰。因此就需要這三個(gè)線程安全的函數(shù):wx.PostEvent, wx.CallAfter和wx.CallLater。據(jù)Robin Dunn(wxPython作者)描述,wx.CallAfter使用了wx.PostEvent來(lái)給應(yīng)用程序?qū)ο蟀l(fā)生事件。應(yīng)用程序會(huì)有個(gè)事件處理程序綁定到事件上,并在收到事件后,執(zhí)行處理程序來(lái)做出反應(yīng)。我認(rèn)為wx.CallLater是在特定時(shí)間后調(diào)用了wx.CallAfter函數(shù),已實(shí)現(xiàn)規(guī)定時(shí)間后發(fā)送事件。

Robin Dunn還指出Python全局解釋鎖 (GIL)也會(huì)避免多線程同時(shí)執(zhí)行python字節(jié)碼,這會(huì)限制程序使用CPU內(nèi)核的數(shù)量。另外,他還說(shuō),“wxPython發(fā)布GIL是為了在調(diào)用wx API時(shí),其他線程也可以運(yùn)行”。換句話說(shuō),在多核機(jī)器上使用多線程,可能效果會(huì)不同。

總之,大概的意思是桑wx函數(shù)中,wx.CallLater是最抽象的線程安全函數(shù), wx.CallAfter次之,wx.PostEvent是最低級(jí)的。下面的實(shí)例,演示了如何使用wx.CallAfter和wx.PostEvent函數(shù)來(lái)更新wxPython程序。

wxPython, Theading, wx.CallAfter and PubSub

wxPython郵件列表中,有些專(zhuān)家會(huì)告訴其他人使用wx.CallAfter,并利用PubSub實(shí)現(xiàn)wxPython應(yīng)用程序與其他線程進(jìn)行通訊,我也贊成。如下代碼是具體實(shí)現(xiàn):

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()


我們會(huì)用time模塊來(lái)模擬耗時(shí)過(guò)程,請(qǐng)隨意將自己的代碼來(lái)代替,而在實(shí)際項(xiàng)目中,我用來(lái)打開(kāi)Adobe Reader,并將其發(fā)送給打印機(jī)。這并沒(méi)什么特別的,但我不用線程的話,應(yīng)用程序中的打印按鈕就會(huì)在文檔發(fā)送過(guò)程中卡住,UI界面也會(huì)被掛起,直到文檔發(fā)送完畢。即使一秒,兩秒對(duì)用戶(hù)來(lái)說(shuō)都有卡的感覺(jué)。

總之,讓我們來(lái)看看是如何工作的。在我們編寫(xiě)的Thread類(lèi)中,我們重寫(xiě)了run方法。該線程在被實(shí)例化時(shí)即被啟動(dòng),因?yàn)槲覀冊(cè)赺_init__方法中有“self.start”代碼。run方法中,我們循環(huán)6次,每次sheep10秒,然后使用wx.CallAfter和PubSub更新UI界面。循環(huán)結(jié)束后,我們發(fā)送結(jié)束消息給應(yīng)用程序,通知用戶(hù)。

你會(huì)注意到,在我們的代碼中,我們是在按鈕的事件處理程序中啟動(dòng)的線程。我們還禁用按鈕,這樣就不能開(kāi)啟多余的線程來(lái)。如果我們讓一堆線程跑的話,UI界面就會(huì)隨機(jī)的顯示“已完成”,而實(shí)際卻沒(méi)有完成,這就會(huì)產(chǎn)生混亂。對(duì)用戶(hù)來(lái)說(shuō)是一個(gè)考驗(yàn),你可以顯示線程PID,來(lái)區(qū)分線程,你可能要在可以滾動(dòng)的文本控件中輸出信息,這樣你就能看到各線程的動(dòng)向。

最后可能就是PubSub接收器和事件的處理程序了:
 

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()


看我們?nèi)绾螐木€程中提取消息,并用來(lái)更新界面?我們還使用接受到數(shù)據(jù)的類(lèi)型來(lái)告訴我們什么顯示給了用戶(hù)。很酷吧?現(xiàn)在,我們玩點(diǎn)相對(duì)低級(jí)一點(diǎn)點(diǎn),看wx.PostEvent是如何辦的。

wx.PostEvent與線程

下面的代碼是基于wxPython wiki編寫(xiě)的,這看起來(lái)比wx.CallAfter稍微復(fù)雜一下,但我相信我們能理解。

import time 
import wx 
   
from threading import Thread 
   
# Define notification event for thread completion 
EVT_RESULT_ID = wx.NewId() 
   
def EVT_RESULT(win, func): 
  """Define Result Event."""
  win.Connect(-1, -1, EVT_RESULT_ID, func) 
   
class ResultEvent(wx.PyEvent): 
  """Simple event to carry arbitrary result data."""
  def __init__(self, data): 
    """Init Result Event."""
    wx.PyEvent.__init__(self) 
    self.SetEventType(EVT_RESULT_ID) 
    self.data = data 
   
######################################################################## 
class TestThread(Thread): 
  """Test Worker Thread Class."""
   
  #---------------------------------------------------------------------- 
  def __init__(self, wxObject): 
    """Init Worker Thread Class."""
    Thread.__init__(self) 
    self.wxObject = wxObject 
    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) 
      amtOfTime = (i + 1) * 10
      wx.PostEvent(self.wxObject, ResultEvent(amtOfTime)) 
    time.sleep(5) 
    wx.PostEvent(self.wxObject, ResultEvent("Thread finished!")) 
   
######################################################################## 
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) 
   
    # Set up event handler for any worker thread results 
    EVT_RESULT(self, self.updateDisplay) 
   
  #---------------------------------------------------------------------- 
  def onButton(self, event): 
    """
    Runs the thread
    """
    TestThread(self) 
    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()


讓我們先稍微放一放,對(duì)我來(lái)說(shuō),最困擾的事情是第一塊:
 

# Define notification event for thread completion 
EVT_RESULT_ID = wx.NewId() 
   
def EVT_RESULT(win, func): 
  """Define Result Event."""
  win.Connect(-1, -1, EVT_RESULT_ID, func) 
   
class ResultEvent(wx.PyEvent): 
  """Simple event to carry arbitrary result data."""
  def __init__(self, data): 
    """Init Result Event."""
    wx.PyEvent.__init__(self) 
    self.SetEventType(EVT_RESULT_ID) 
    self.data = data


EVT_RESULT_ID只是一個(gè)標(biāo)識(shí),它將線程與wx.PyEvent和“EVT_RESULT”函數(shù)關(guān)聯(lián)起來(lái),在wxPython代碼中,我們將事件處理函數(shù)與EVT_RESULT進(jìn)行捆綁,這就可以在線程中使用wx.PostEvent來(lái)將事件發(fā)送給自定義的ResultEvent了。

結(jié)束語(yǔ)

希望你已經(jīng)明白在wxPython中基本的多線程技巧。還有其他多種多線程方法這里就不在涉及,如wx.Yield和Queues。幸好有wxPython wiki,它涵蓋了這些話題,因此如果你有興趣可以訪問(wèn)wiki的主頁(yè),查看這些方法的使用。

相關(guān)文章

  • python爬蟲(chóng)進(jìn)階之協(xié)程詳解

    python爬蟲(chóng)進(jìn)階之協(xié)程詳解

    這篇文章主要介紹了python爬蟲(chóng)進(jìn)階之協(xié)程詳解,coroutine中文翻譯叫協(xié)程,在 Python 中昌指代為協(xié)程對(duì)象類(lèi)型,可以將協(xié)程對(duì)象注冊(cè)到時(shí)間循環(huán)中被調(diào)用,需要的朋友可以參考下
    2023-08-08
  • python樹(shù)的同構(gòu)學(xué)習(xí)筆記

    python樹(shù)的同構(gòu)學(xué)習(xí)筆記

    在本篇文章里小編給大家整理的是一篇關(guān)于python樹(shù)的同構(gòu)學(xué)習(xí)筆記以及相關(guān)實(shí)例代碼內(nèi)容,有需要的朋友們學(xué)習(xí)下。
    2019-09-09
  • python3.4+pycharm 環(huán)境安裝及使用方法

    python3.4+pycharm 環(huán)境安裝及使用方法

    這篇文章主要介紹了python3.4+pycharm 環(huán)境安裝及使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • python+django+selenium搭建簡(jiǎn)易自動(dòng)化測(cè)試

    python+django+selenium搭建簡(jiǎn)易自動(dòng)化測(cè)試

    這篇文章主要介紹了python+django+selenium搭建簡(jiǎn)易自動(dòng)化測(cè)試,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Python定義空函數(shù)的6種方法小結(jié)

    Python定義空函數(shù)的6種方法小結(jié)

    本文主要介紹了Python中定義空函數(shù)的6種方法,包括注釋、pass、return、Ellipsis等,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • 6種將Python代碼打包成exe應(yīng)用的方式

    6種將Python代碼打包成exe應(yīng)用的方式

    這篇文章主要給大家介紹了關(guān)于6種將Python代碼打包成exe應(yīng)用的方式,對(duì)于很多python的初學(xué)者來(lái)說(shuō),很希望將自己用python寫(xiě)的.py文件生成exe直接在電腦上運(yùn)行,需要的朋友可以參考下
    2023-08-08
  • python 有效的括號(hào)的實(shí)現(xiàn)代碼示例

    python 有效的括號(hào)的實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了python 有效的括號(hào)的實(shí)現(xiàn)代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • pycharm 取消默認(rèn)的右擊運(yùn)行unittest的方法

    pycharm 取消默認(rèn)的右擊運(yùn)行unittest的方法

    今天小編就為大家分享一篇pycharm 取消默認(rèn)的右擊運(yùn)行unittest的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • PyCharm中New Directory 和 New Python Package的區(qū)別解析

    PyCharm中New Directory 和 New Python 

    python package這是一個(gè)特殊的目錄,因?yàn)樵趧?chuàng)建該python package的時(shí)候,系統(tǒng)會(huì)自動(dòng)地生成一個(gè)py文件, init.py,這篇文章主要介紹了PyCharm中New Directory 和 New Python Package的區(qū)別,需要的朋友可以參考下
    2023-12-12
  • 用Flask實(shí)現(xiàn)token登錄校驗(yàn)的解決方案

    用Flask實(shí)現(xiàn)token登錄校驗(yàn)的解決方案

    網(wǎng)站、小程序、APP 是否已經(jīng)登錄所代表的狀態(tài),代表一個(gè)概念是登錄態(tài), 我們常用的登錄態(tài)驗(yàn)證方式有cookie,session,token,token提供了另外一種不需要緩存賬戶(hù)和密碼的登錄狀態(tài)驗(yàn)證方式,本文給大家介紹了用Flask實(shí)現(xiàn)token登錄校驗(yàn)的解決方案,需要的朋友可以參考下
    2024-03-03

最新評(píng)論

岑巩县| 墨江| 新龙县| 蓬溪县| 渝中区| 敦化市| 交口县| 军事| 通化县| 天气| 陇南市| 尖扎县| 会同县| 铅山县| 凉城县| 临泽县| 桐柏县| 涿鹿县| 汉阴县| 昆山市| 雅江县| 霍城县| 常山县| 达尔| 翼城县| 公主岭市| 祁连县| 石门县| 裕民县| 宁蒗| 横峰县| 当涂县| 吴江市| 青海省| 大理市| 泾川县| 潼南县| 兴城市| 措勤县| 肥城市| 若羌县|