WxPython multithreading support

Source: Internet
Author: User

If you often use python to develop GUI programs, you will know that sometimes it takes a long time to execute a task. Of course, if you use a command line program, you are surprised. In most cases, this will block the GUI event loop and the user will see that the program is stuck. How can this situation be avoided? Of course it's using threads or processes! In this article, we will explore how to use the wxPython and theading modules. The wxpython thread security method wxPython contains three "thread security" functions. If none of the three functions are used when you update the UI, you may encounter a strange problem. Sometimes the GUI runs normally, but sometimes it crashes for no reason. Therefore, these three thread-safe functions are required: wx. PostEvent, wx. CallAfter, and wx. CallLater. According to Robin Dunn (author of wxPython), wx. CallAfter uses wx. PostEvent to send an event to an application object. An application will bind an event handler to the event and execute the handler to respond to the event. In my opinion, wx. CallLater calls the wx. CallAfter function after a specific time, and sends an event after the specified time has been implemented. Robin Dunn also pointed out that the Python global interpretation lock (GIL) will also avoid multiple threads executing python bytecode at the same time, which will limit the number of CPU cores used by the program. In addition, he also said, "wxPython released GIL to run other threads when calling the wx API ". In other words, multithreading on a multi-core machine may have different effects. In short, the general meaning is that in the sanwx function, wx. CallLater is the most abstract thread security function, followed by wx. CallAfter, and wx. PostEvent is the lowest level. The following example demonstrates how to use the wx. CallAfter and wx. PostEvent functions to update the wxPython program. WxPython, Theading, wx. in the CallAfter and PubSubwxPython email list, some experts will tell others to use wx. callAfter and use PubSub to implement wxPython applications to communicate with other threads. I also agree. The following code is specific: [python] 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 () # sta Rt 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! ") # Effecdef 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 = 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): "" es 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 replace your code at will. In actual projects, I used to open Adobe Reader and send it to the printer. This is nothing special, but if I don't need a thread, the print button in the application will be stuck during the document sending process, and the UI will also be suspended until the document is sent completely. Even if one second or two seconds are stuck. In short, let's see how it works. In the Thread class we wrote, we override the run method. This thread is started when it is instantiated, because we have "self. start" code in the _ init _ method. In the run method, we loop 6 times, each time sheep10 seconds, and then use wx. CallAfter and PubSub to update the UI. After the loop ends, we send the End message to the application to notify users. You will notice that in our code, we start the thread in the event handler of the button. We also disable the button so that we cannot enable unnecessary threads. If we run a bunch of threads, the UI will randomly display "completed", but it is not completed, which will lead to confusion. It is a test for users. You can display the thread PID to differentiate threads. You may need to output information in the scrolling text control so that you can see the movements of various threads. Finally, it may be the PubSub receiver and event handler: [python] def updateDisplay (self, msg ): "elasticsearch 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 (): How do we extract messages from the thread and update the interface? We also use the accepted data type to tell us what is displayed to the user. Cool, right? Now, let's take a look at how wx. PostEvent works. Wx. PostEvent and the code below the thread are written based on wxPython wiki, which looks a little more complicated than wx. CallAfter, but I believe we can understand it. [Python] 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. setEv EntType (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 = 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): "" es 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. for me, the most troublesome thing is the first one: [python] # 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 eve Nt 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 is only an identifier, which associates the thread with wx. pyEvent is associated with the "EVT_RESULT" function. In the wxPython code, we bind the event handler function with the EVT_RESULT, so that wx can be used in the thread. postEvent sends the event to the custom ResultEvent. In conclusion, I hope you understand the basic multithreading skills in wxPython. Other multi-threaded methods are not involved here, such as wx. Yield and Queues. Fortunately, wxPython wiki covers these topics. Therefore, if you are interested, visit the wiki homepage to view the usage of these methods.

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.