473,385 Members | 1,564 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

wxPython and threads again

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
?
( I have to wait, otherwise I will work uncompleted files )

Any way to work around it?
Thanks.

Aug 10 '05 #1
9 3238
In article <11*********************@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
Aug 10 '05 #2
David E. Konerding DSD staff wrote:
[...]
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 way-cool things to transmit, in either the queue or the
event data, are tuples of:

(func, args, kwargs)

The so-called-'main' thread gets these, and blindly calls
func(*args, **kwargs). Since only the main thread can safely
update the GUI, other threads pass GUI-updating functions to be
called by the main thread.

The technique is beautifully general. The worker thread does
it's long, blocking operations independently, and when it needs
to update the GUI it sends the main thread a quick, non-blocking
function.

In wxPython, custom events can carry arbitrary data, so the easy
thing to do is just pass the (func, args, kwargs) across with
wxPostEvent (or so I've read; I'm not a wxPython user).

TkInter has no equivalent to wxPostEvent. Contrary to popular
belief, TkInter's event_generate is not thread-safe. The usual
TkInter solution is a queue, which the main thread periodically
polls via the 'after' function.

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.

I couldn't disagree more about that being easier and simplifying
the code. "Creating a whole thread" is trivial.
--
--Bryan
Aug 10 '05 #3
David E. Konerding DSD staff wrote:
Further, calling wx from a thread other than the one running the event
loop is deep voodoo and should typically be avoided.
"Typically"? Let's just say "always" and maybe use the phrase "certain
to corrupt wx and crash the app" instead of "deep voodoo". :-) At least
that way the OP won't waste time experimenting...
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.


Even simpler for some purposes is wx.CallAfter(), which provides the
asynchronous performance of wxPostEvent with the "beautifully general"
approach of passing callables through a Queue which Bryan Olson
described in his post. (That is, you don't need to do polling with a
non-blocking get() on the Queue this way.)

-Peter
Aug 10 '05 #4
thanks for all these advices.
I think a custom event will be the way to go.
for the moment I use something _really_ ugly : a mix between GUI,
threads and recursive fonctions.

Aug 10 '05 #5
Peter Hansen wrote:
David E. Konerding DSD staff wrote:
Further, calling wx from a thread other than the one running the
event loop is deep voodoo and should typically be avoided.
"Typically"? Let's just say "always" and maybe use the phrase "certain
to corrupt wx and crash the app" instead of "deep voodoo". :-) At least
that way the OP won't waste time experimenting...


Come to think of it, wouldn't it be a good idea for a GUI
toolkit to to do something like:

import thread

# ...

def WhateverToolKitInitFunction(*args):
global _thread_of_record
_thread_of_record = thread.get_ident()
# ...
def check_thread():
if thread.get_ident() != _thread_of_record:
raise RuntimeError('Attempt to update GUI from foreign
thread.')
And then begin each non-thread-safe function like:
def SomeUpdateFunction(*args):
check_thread()
# ...
[...] Even simpler for some purposes is wx.CallAfter(),


Ah, Nice. Same method under the hood, but hides the complexity.
--
--Bryan
Aug 11 '05 #6
David E. Konerding DSD staff wrote:
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.


Or, don't use threadedselectreactor, but instead just use normal
threading and reactor.callFromThread.
Aug 11 '05 #7
On 2005-08-10, Bryan Olson <fa*********@nowhere.org> wrote:
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.

I couldn't disagree more about that being easier and simplifying
the code. "Creating a whole thread" is trivial.


I've done both styles. Actually, I greatly prefer the single threaded approach now; conceptually,
the threaded approach is very simple, but your program ends up getting complex because the data-passing
infrastructure. And you end up structuring your logic in somewhat more convoluted ways. And
most people have such a hard time dealing with data synch between threads...

Dave
Aug 11 '05 #8
On 2005-08-10, Peter Hansen <pe***@engcorp.com> wrote:
David E. Konerding DSD staff wrote:
Further, calling wx from a thread other than the one running the event
loop is deep voodoo and should typically be avoided.
"Typically"? Let's just say "always" and maybe use the phrase "certain
to corrupt wx and crash the app" instead of "deep voodoo". :-) At least
that way the OP won't waste time experimenting...


Not really certain:
http://wxwidgets.org/manuals/2.6.1/w...hreadfunctions

This strongly suggests you can arbitrarily grab the wx GUI lock and call GUI
functions from any thread. It's still voodoo. But we're adults here, and practicing
voodoo isn't proscribed.
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.


Even simpler for some purposes is wx.CallAfter(), which provides the
asynchronous performance of wxPostEvent with the "beautifully general"
approach of passing callables through a Queue which Bryan Olson
described in his post. (That is, you don't need to do polling with a
non-blocking get() on the Queue this way.)


Very good point. I wasn't aware CallAfter had those semantics; I always used it from
the main thread. But won't wx.CallAfter cause a bit of a delay since it will wait until
all pending events are processed and only handle the function afterwards, thus inducing
an extra event loop cycle/redraw?

Dave
Aug 11 '05 #9
David E. Konerding DSD staff wrote:
http://wxwidgets.org/manuals/2.6.1/w...hreadfunctions

This strongly suggests you can arbitrarily grab the wx GUI lock and call GUI
functions from any thread. It's still voodoo. But we're adults here, and practicing
voodoo isn't proscribed.
Oh, very nice... for my automatic testing requirements anyway. I did
not know those existed...

I agree using this in real code is probably not wise, and you're right
that it is best described as "voodoo". :)
But won't wx.CallAfter cause a bit of a delay since it will wait until
all pending events are processed and only handle the function afterwards,
thus inducing an extra event loop cycle/redraw?


Since it's built on PostEvent, it will do whatever happens with other
stuff that is PostEvent-ed, I suppose. Your description is probably
accurate...

-Peter
Aug 11 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: fooooo | last post by:
This is a network app, written in wxPython and the socket module. This is what I want to happen: GUI app starts. User clicks a button to 'start' the work of the app. When start is pressed, a new...
6
by: Zunbeltz Izaola | last post by:
Hi, I have the following problem. I'm developing a GUI program (wxPython). This program has to comunicate (TCP) whit other program that controls a laboratory machine to do a measurement. I...
9
by: Tyler | last post by:
Hello All: I am currently working on a project to create an FEM model for school. I was thinking about using wxPython to gather the 12 input variables from the user, then, after pressing the...
2
by: Kevin Walzer | last post by:
I'm porting a Tkinter application to wxPython and had a question about wxPython's event loop. The Tkinter app provides a GUI to a command-line tool. It gathers user input, and opens an...
1
by: Benjamin | last post by:
Hello! I am writing a search engine with wxPython as the GUI. As the search thread returns items, it adds them to a Queue which is picked up by the main GUI thread calling itself recursively with...
4
by: Jimmy | last post by:
Hi, wxPython is cool and easy to use, But I ran into a problem recently when I try to write a GUI. The thing is I want to periodically update the content of StatixText object, so after create...
12
by: bullockbefriending bard | last post by:
I am a complete ignoramus and newbie when it comes to designing and coding networked clients (or servers for that matter). I have a copy of Goerzen (Foundations of Python Network Programming) and...
3
by: mistersulu | last post by:
Hi all: I'm using a wx.ListView object with a multi-threaded wxPython app. The list is dynamically generated and accessed across two or more threads. In spite of the fact that I have checks to...
0
by: Stef Mientki | last post by:
Peter Anderson wrote: In PyScripter, you should run wxPython in the plain remote machine (not the wxPython remote), and you should set "reset before run flag" or reset the remote machine each...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.