Analysis of Python programming using Wxpython to support multithreading methods _python

Source: Internet
Author: User
Tags thread class

If you often use Python to develop GUI programs, then you know that sometimes it takes a long time to perform a task. Of course, you'll be surprised if you use a command-line program. In most cases, this will clog the GUI's event loop, and the user will see the program die. How can we avoid such a situation? Of course it is using threads or processes! In this article, we will explore how to implement using Wxpython and theading modules.

Wxpython Thread-Safe method

In Wxpython, there are three "thread-safe" functions. If you are updating the UI interface, three functions are not used, then you may encounter strange problems. Sometimes the GUI is busy running quite normal, sometimes it crashes for no reason. So you need these three thread-safe functions: WX. Postevent, WX. Callafter and Wx.calllater. According to Robin Dunn (Wxpython author), WX. Callafter uses wx.postevent to give an event to an Application object. The application will have an event handler bound to the event and, after receiving the event, execute the handler to respond. I think WX. Calllater calls the Wx.callafter function after a certain time, and the event is sent after the specified time has been implemented.

Robin Dunn also points out that the Python global Interpretation Lock (GIL) also avoids multithreading executing python bytecode at the same time, which limits the number of programs using the CPU kernel. In addition, he added, "Wxpython the Gil is for other threads to run when the WX API is invoked." In other words, using multiple threads on multi-core machines may have different effects.

In short, presumably it means the Mulberry wx function, WX. Calllater is the most abstract thread-safe function, WX. Callafter Second, WX. The postevent is the lowest. The following example shows how to use WX. Callafter and Wx.postevent functions to update the Wxpython program.

WxPython, Theading, WX. Callafter and PubSub

In the

Wxpython mailing list, some experts tell others to use WX. Callafter, and I also agree to use PubSub to implement Wxpython applications to communicate with other threads. The following code is a concrete implementation:

Import time Import WX-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 (a) 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) * 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 pan El = wx. Panel (self, wx.id_any) Self.displaylbl = wx. Statictext (panel, label= "Amount of time since thread started goes") 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 Thre
 Ad "" "   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 ()


We will use the time module to simulate the time-consuming process, please feel free to replace the code, and in the actual project, I used to open Adobe Reader, and send it to the printer. This is nothing special, but if I don't use threads, the Print button in the application will get stuck in the process of sending the document and the UI interface will be suspended until the document is sent. Even a second, two seconds to the user has a card feeling.

Anyway, let's see how it works. In the thread class we wrote, we rewrote the Run method. The thread is started when instantiated, because we have "Self.start" code in the __init__ method. In the Run method, we loop 6 times, sheep10 seconds at a time, and then use WX. Callafter and PubSub update UI interface. After the loop completes, we send an end message to the application notifying the user.

You will notice that in our code we are the threads that are started in the button's event handler. We also disable the button so that we can't open the extra threads. If we let a bunch of threads run, the UI interface would randomly display "completed" and not actually complete, which would create confusion. A test for users, you can display thread PID to differentiate threads, you might want to output information in a text control that can be scrolled, so you can see the movements of threads.

The end may be the PubSub receiver and the handler for the event:

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


See how we extract messages from threads and use them to update the interface? We also use a type that accepts data to tell us what is displayed to the user. Pretty cool, huh? Now, let's play a little bit relatively low and see WX. Postevent is how to do it.

Wx. Postevent and Threads

The following code is written based on the Wxpython wiki, which looks better than WX. Callafter a little bit more complicated, but I'm sure we can understand.

Import time import WX/threading Import Thread # Define notification event for Thread completion Evt_resu lt_id = wx.
  NewId () def evt_result (Win, Func): "" "Define result Event." " Win. Connect ( -1,-1, evt_result_id, Func) class Resultevent (WX.
  pyevent): "" "" "" "" "" "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 Work
    Er Thread Class. "" " Thread.__init__ (self) self.wxobject = Wxobject Self.start () # Start the thread #------------------------
    ----------------------------------------------def run (self): "" "Run Worker Thread." " # TThe ' is ' the code executing in the new thread. For I in range (6): Time.sleep (a) Amtoftime = (i + 1) * 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 pan El = wx. Panel (self, wx.id_any) Self.displaylbl = wx. Statictext (panel, label= "Amount of time since thread started goes") 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 to 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 ()


Let's put it a little bit first, for me, the most troubling thing is the first one:

# 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): "" "" "" "" "" " 
  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 is just an identity, it will thread with WX. Pyevent is associated with the "Evt_result" function, in the Wxpython code, we bundle the event handler function with the Evt_result, which allows WX to be used in threads. Postevent to send the event to the custom resultevent.

Conclusion

I hope you already understand the basic multithreading techniques in Wxpython. There are many other multi-threaded methods here that are not involved, such as WX. Yield and queues. Fortunately there is a Wxpython wiki that covers these topics, so if you are interested in having access to the wiki's homepage, see how these methods are used.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.