threads and exception in wxPython

  • Thread starter Zunbeltz Izaola
  • Start date
J

Josiah Carlson

Jeff Shannon said:
Another possibility is to check the queue in an idle-event handler.
When you place something in the queue, you can call wx.WakeUpIdle() to
ensure that the main thread will do idle processing at its soonest
opportunity.

The only ugly part about idle handling is that idle handlers are called
quite often (at least in the wxPython versions I've run). Specifically,
whenever I move my mouse over a wxPython app window, idle events are
streamed to the idle event handler at 30-60 events/second.

Not really a big deal, but something people should know about none the
less.


- Josiah

#source I used, lack of new namespace the result of copy/paste from
#wxPython wiki

from wxPython.wx import wxPySimpleApp, wxFrame, EVT_IDLE
import time

class myframe(wxFrame):
def __init__(self, *args, **kwargs):
wxFrame.__init__(self, *args, **kwargs)
self.t = None
EVT_IDLE(self, self.idle_handler)

def idle_handler(self, evt):
if self.t is None:
self.t = time.time()
else:
print round(time.time()-self.t, 3),
self.t = time.time()
evt.Skip()

app = wxPySimpleApp()
frame = myframe(None, -1, "Ugly Idle Handling")
frame.Show(1)
app.MainLoop()


#output on win2k, Python 2.3.2, wxPython 2.4.2.4 while wiggling my
#mouse over the window...

C:\Temp>test_idle.py
1.828 0.016 0.015 0.032 0.015 0.016 0.015 0.032 0.031 0.016 0.406 0.547 0.031 0.
016 0.015 0.016 0.015 0.016 0.016 0.015 0.016 0.016 0.015 0.016 0.015 0.016 0.01
6 0.015 0.016 0.016 0.015 0.016 0.015 0.016 0.015 0.016 0.016 0.015 0.016 0.015
0.016 0.016 0.015 0.016 0.016 0.015 0.016 0.015 0.016 0.016 0.015 0.016 0.016 0.
015 0.016 0.015 0.016 0.016 0.015 0.016 0.016 0.015 0.016 0.015 0.016 0.016 0.01
6 0.016 0.015 0.016 0.015 0.016 0.016 0.015 0.016 0.016 0.015 0.016 0.015 0.016
0.016 0.015 0.016 0.016 0.015 0.016 0.015 0.016 0.016 0.015 0.016 0.016 0.015 0.
016 0.015 0.016 0.016 0.015 0.016 0.015 0.016 0.015 0.016 0.016 0.015 0.016 0.01
6 0.015 0.016 0.015 0.016 0.016 0.015 0.016 0.016 0.015 0.016 0.015 0.016

C:\Temp>
 
J

Jeff Shannon

Josiah said:
The only ugly part about idle handling is that idle handlers are called
quite often (at least in the wxPython versions I've run). Specifically,
whenever I move my mouse over a wxPython app window, idle events are
streamed to the idle event handler at 30-60 events/second.

Not really a big deal, but something people should know about none the
less.

True enough. I believe that in most cases, checking a queue for content
and acting if there's something there should be a fairly negligible
load, and that typically it's a load that happens only when nothing else
would be happening anyhow. But it *is* something to be aware of, and
one should be at least somewhat cautious about what's done during idle
processing. OTOH, it's a bit simpler to implement than creating a
custom event and installing a handler for that... Not *much* simpler, as
creating a custom event isn't exactly difficult, but in simple
circumstances it has its benefits... :)

(For those unfamiliar with wxPython's/wxWidgets' idle processing -- idle
events are triggered every time an application's event queue *becomes*
empty. This means that if you get a few mouse events, and process them,
then get a few more and process them... you get an idle event in between
each batch of mouse events, and possibly between each individual mouse
event depending on how fast your particular machine processes them. But
every time you get an idle event, it's because your app has nothing else
to deal with at that moment in time. It also means that if your window
is in the background and not getting any new events in the queue, the
queue will never switch from full to empty, and you won't get any idle
events. That's what wx.WakeUpIdle() is for -- to simulate the queue
emptying and thus triggering an idle event.)

Jeff Shannon
Technician/Programmer
Credit International
 
J

Josiah Carlson

Jeff Shannon said:
True enough. I believe that in most cases, checking a queue for content
and acting if there's something there should be a fairly negligible
load, and that typically it's a load that happens only when nothing else
would be happening anyhow. But it *is* something to be aware of, and
one should be at least somewhat cautious about what's done during idle
processing. OTOH, it's a bit simpler to implement than creating a
custom event and installing a handler for that... Not *much* simpler, as
creating a custom event isn't exactly difficult, but in simple
circumstances it has its benefits... :)

Who said anything about a custom event? Timers are useful and so very
easy to use.

- Josiah


#example code...
from wxPython.wx import wxPySimpleApp, wxFrame, wxTimer, wxNewId, EVT_TIMER
import time

class myframe(wxFrame):
def __init__(self, *args, **kwargs):
wxFrame.__init__(self, *args, **kwargs)
self.t = None
tid = wxNewId()
self.tim = wxTimer(self, tid)
self.tim.Start(1000, False)
EVT_TIMER(self, tid, self.idle_handler)

def idle_handler(self, evt):
if self.t is None:
self.t = time.time()
else:
print round(time.time()-self.t, 3),
self.t = time.time()

app = wxPySimpleApp()
frame = myframe(None, -1, "Ugly Idle Handling")
frame.Show(1)
app.MainLoop()
 
J

Jeff Shannon

Josiah said:
Who said anything about a custom event?

Several people earlier in this thread did -- Jaime Wyant and Michael
Hobbs, for instance. :)

So we have at least three viable ways of doing it, each with their own
advantages/disadvantages. Which one to use depends on circumstances and
personal preference...

Jeff Shannon
Technician/Programmer
Credit International
 
P

Peter Hansen

(Sorry if duplicate: NTTP server screwed up.)

Peter said:
I should note for the record that neither Thomas'
example above nor even my more complex one
... implements the required API fully.

A further addendum, or a caution/concern:

The docs also say that you should own the GIL when
you call this routine. I suspect that in fact you
are supposed to have a lock on the GIL during the
_entire time_ that you are working with this routine,
specifically around all the following (pseudo)code:

n = PyThreadState_SetAsyncExc(id, Py_Object *)
if n > 1:
PyThreadState_SetAsyncExc(id, NULL)

I suspect that the only reason the second call works
(supposedly it "reverts the effects" of the first call)
is because the interpreter has not had time to execute
any more bytecodes in the affected threads. But since
the precise definition of this "reversion" is undocumented,
going to the source or an expert (which I'm clearly not)
would be the only way to sort out such "minor" issues...

-Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

save an opengl canvas (wxPython) 2
handle a log file. 3
Using ConfigParse 5

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top