激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - 分析Python編程時利用wxPython來支持多線程的方法

分析Python編程時利用wxPython來支持多線程的方法

2020-05-31 10:39腳本之家 Python

這篇文章主要介紹了Python編程時利用wxPython來支持多線程的方法,本文主要以開發GUI程序時做線程通訊作為一個示例來講解,需要的朋友可以參考下

如果你經常使用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應用程序與其他線程進行通訊,我也贊成。如下代碼是具體實現:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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()


我們會用time模塊來模擬耗時過程,請隨意將自己的代碼來代替,而在實際項目中,我用來打開Adobe Reader,并將其發送給打印機。這并沒什么特別的,但我不用線程的話,應用程序中的打印按鈕就會在文檔發送過程中卡住,UI界面也會被掛起,直到文檔發送完畢。即使一秒,兩秒對用戶來說都有卡的感覺。

總之,讓我們來看看是如何工作的。在我們編寫的Thread類中,我們重寫了run方法。該線程在被實例化時即被啟動,因為我們在__init__方法中有“self.start”代碼。run方法中,我們循環6次,每次sheep10秒,然后使用wx.CallAfter和PubSub更新UI界面。循環結束后,我們發送結束消息給應用程序,通知用戶。

你會注意到,在我們的代碼中,我們是在按鈕的事件處理程序中啟動的線程。我們還禁用按鈕,這樣就不能開啟多余的線程來。如果我們讓一堆線程跑的話,UI界面就會隨機的顯示“已完成”,而實際卻沒有完成,這就會產生混亂。對用戶來說是一個考驗,你可以顯示線程PID,來區分線程,你可能要在可以滾動的文本控件中輸出信息,這樣你就能看到各線程的動向。

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

?
1
2
3
4
5
6
7
8
9
10
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()


看我們如何從線程中提取消息,并用來更新界面?我們還使用接受到數據的類型來告訴我們什么顯示給了用戶。很酷吧?現在,我們玩點相對低級一點點,看wx.PostEvent是如何辦的。

wx.PostEvent與線程

下面的代碼是基于wxPython wiki編寫的,這看起來比wx.CallAfter稍微復雜一下,但我相信我們能理解。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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()


讓我們先稍微放一放,對我來說,最困擾的事情是第一塊:
 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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只是一個標識,它將線程與wx.PyEvent和“EVT_RESULT”函數關聯起來,在wxPython代碼中,我們將事件處理函數與EVT_RESULT進行捆綁,這就可以在線程中使用wx.PostEvent來將事件發送給自定義的ResultEvent了。

結束語

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

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 亚洲午夜视频在线 | 国产一区二区三区四区精 | 九九热在线视频观看这里只有精品 | 一级做a爱片久久毛片a高清 | 国产一区亚洲 | 黄色一级毛片免费看 | 久久久精品视 | 久久视频国产 | 国内精品久久久久久久久久 | 国产一区二区在线免费播放 | 99精品视频久久精品视频 | 性生活视频软件 | 中文字幕一二区 | 91精品国产99久久久久久红楼 | 在线播放h | 亚洲欧美不卡视频 | 91精品老司机 | 天堂在线中文资源 | 国产69精品久久久久久久久久 | 国产人成精品一区二区三 | 中国成人在线视频 | av中文在线观看 | 日本黄色大片免费 | 国产乱弄 | 在线中文日韩 | 成人国产免费观看 | 黄污网址 | 最新亚洲国产 | 毛片中文字幕 | 久久国产综合精品 | 欧美性生交大片 | 一级美女大片 | 国产精品久久久久久久娇妻 | 宅男噜噜噜66国产免费观看 | 毛片大全免费看 | 手机黄色小视频 | 欧美视频国产 | 亚洲精品久久久久久久久久久 | 国产99一区二区 | 国产91对白叫床清晰播放 | 一级电影免费看 |