国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看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 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 日韩高清av | 久久综合av| 一区二区三区免费观看 | 亚洲国产aⅴ精品一区二区 少妇一级片免费看 | 亚洲一区二区三区免费观看 | 91特片网| 黄色一级片毛片 | 九九亚洲| 国产精品影视在线观看 | 99视频精品 | 伊人网网站| 91精品国产综合久久婷婷香蕉 | 亚洲国产精品视频 | 国产一区二区三区午夜 | 日韩国产精品一区二区三区 | 久久综合久 | 亚洲一区二区在线 | 日韩一二三区 | 欧美激情精品久久久久久黑人 | www国产网站 | 国产精品成人一区二区三区夜夜夜 | 男人午夜天堂 | 久久久国产视频 | 午夜天 | 国产精品久久精品 | 亚洲一区中文字幕 | 午夜视频在线免费观看 | 欧美激情小视频 | 国产一区二区三区在线 | 成人免费在线观看视频 | 国产欧美精品一区二区三区四区 | 成人欧美一区二区三区白人 | 久久一日本道色综合久久 | 人妖一区 | 欧美视频免费 | 性视频一区二区 | 亚洲午夜激情 | 亚洲精品久久久久久下一站 | 日韩欧美中文在线观看 | 免费三级网站 | 欧美一区二区高清视频 |