wxPython and threads again

David E. Konerding DSD staff dek at bosshog.lbl.gov
Wed Aug 10 19:07:00 CEST 2005


In article <1123683323.056092.92800 at o13g2000cwo.googlegroups.com>, perchef wrote:
> Hi,
> 
> I have several files to download and a GUI to update. I know this is a
> frequently asked question but i can't find an appropriate solution.
> My Downloader extends threading.Thread and update a wx.Gauge in GUI
> during the process.
> 
> for src in urls:
>        downloader = Downloader( src, destination, GUI )
>        downloader.start()
> 
> #work with the downloaded files...
> 
> If i don't use a downloader.join() in this for loop, I launch several
> threads at the same time and so my wx.Gauge is bouncing up and down.
> If i do add the downloader.join() my GUI is no more updated ( in fact,
> nothing appears, it's frozen )
> How can I wait the end of the thread and also be able to update the GUI

Well, the constraints are this: the main thread is running the wx main loop,
and thus, cannot block by calling join on the downloader thread.  Further, calling
wx from a thread other than the one running the event loop is deep voodoo and should typically
be avoided.

You need another way to pass completion information between the downloader
thread and the main thread; the simplest way is to define a custom wx
Event, and wxPostEvent from the downloader thread when it completes (
and when the gauge should be updated).  wxPostEvent is safe to call from non-eventloop threads.
The main thread's wx event loop just spins, properly updating all other
parts of the GUI, and receiving events from the downloader thread.

ANother approach is to have a thread-safe Queue and have the main thread/event loop
poll the queue with queue.get_nowait() periodically (typically 0.1-1 sec).
The downloader thread shares the queue object and puts data structures (typically
class instances, strings, or ints) that indicate status updates.

The easiest approach, though, is to use the threadedselectreactor in Twisted (you need
to check the HEAD branch out with subversion, because that reactor isn't included in any releases).
With threadedselectreactor, it's easy to incorporate both the GUI event loop and the twisted reactor.
Twisted already includes lots of code for doing asynchronous callback-style IO for
IO bound processes like downloading.  Further, you don't even think in an explicitly threaded way-
createing a whole thread just to manage a download process which is motly IO and a little bookkeeping is
silly.  Twisted's approach just makes a lot more sense and simplifies the code too.

Dave



More information about the Python-list mailing list