Pausing a program - poll/sleep/threads?

S

Simon John

I'm writing a PyQt network client for XMMS, using the InetCtrl plugin,
that on connection receives a track length.

To save on bandwidth, I don't want to be continually querying the
server for updates (e.g. has the current track finished yet?) so I
figured the best thing to do is just update after the track length has
expired.

So, how would I make a Python program automatically call a function
after a preset period of time, without the Python process running in
the foreground (effectively single-tasking)?

I think that sleep() would work in the foreground (kind of like a while
loop does, I've come across that issue with wxPython!) does Python have
any polling capabilities?

What about threading - if I launched a thread to just "wait" until a
time has expired, could I then get that thread to make the main program
call a function, or would the main program sit there waiting for the
thread to end? I really have no experience with threads in Python, any
hints/tutorials, the docs are pretty limited?

I'm looking to make this program cross-platform, it has to run on at
least Windows and Linux (hopefully MacOSX too) so the solution would
have to be portable (does Windows even have threading without POSIX?)

If you want to check out what I've done so far (GUI, track info,
controls etc.) you'll need XMMS, http://inetctrl.sourceforge.net and my
source from http://www.the-jedi.co.uk/downloads/xmmsclient there's also
some Windows binaries built with the Cygwin/KDE port.

[InetCtrl seems to segfault if you don't have a playlist loaded, so
load a playlist first, then enable the general plugin. I must submit a
bug report to the author, maybe I could convince him to broadcast when
a track ends...]

Any help would be excellent, as playlist support and these "timed
updates" are about all that's left needing to be done....
 
P

Paul Rubin

Simon John said:
So, how would I make a Python program automatically call a function
after a preset period of time, without the Python process running in
the foreground (effectively single-tasking)?

See the signal module and use the alarm signal.
 
H

Harlin

import time

play_something()

time.sleep(LengthOfSongInSeconds)

do_something()


Have you tried that? I'd be interesting in seeing this app you have. !
 
S

Simon John

I don't think time.sleep() will work too well, I think it will cause
the program to hang around in the foreground, and prevent the GUI
updating.

I'll give it a try just to make sure, as I can't figure out the
signal/alarm thing (the alarm only seems to trigger when I click a
button, not after n-seconds....
 
S

Simon John

Damn! signal is not supported on Windows.

time.sleep() doesn't work, as I suspected::

def info(self):
sleep(5)
self.info()

Basically causes the function to pause, then call itself again, all in
the foreground :-(

I'm thinking some sort of thread timer is the way to go, but really
don't understand threads....
 
J

Jeff Shannon

Simon said:
I'm writing a PyQt network client for XMMS, using the InetCtrl plugin,
that on connection receives a track length.

[...]

So, how would I make a Python program automatically call a function
after a preset period of time, without the Python process running in
the foreground (effectively single-tasking)?

I'm not familiar with Qt/PyQt myself, but the GUI toolkits I *am*
familiar with all have a concept of a timer. Basically, you create a
timer that, when the specified amount of time has elapsed, will either
deliver an event/message to your application's event queue or will
directly call the callback function you provide.

However, I'd suggest that you may not want to wait for the entire
length of the current track, especially if some other process or user
(on any machine) may have access to the same XMMS application. What
happens when, after the song's been playing for a few seconds, someone
skips to the next track? Presumably, you'll want your network client
to detect that and update appropriately. This implies that you should
check back in with the XMMS "server" every few seconds at least. (You
can still use a timer to do this; just have it fire periodically every
second or so, rather than only after several minutes.)

Jeff Shannon
 
S

Simon John

Hmm, yes I had thought of looking around PyQt for a timer, forgot about
it though.

As far as querying the server every few seconds, it does make sense
(you don't miss events) and is the recommended way of doing things with
InetCtrl, but I'd prefer to save the bandwidth/server load than have
realtime status updates.

The status also updates whenever you send a command (like play/pause).

I'm really stuck on how to implement this now....
 
J

Jeff Shannon

Simon said:
As far as querying the server every few seconds, it does make sense
(you don't miss events) and is the recommended way of doing things with
InetCtrl, but I'd prefer to save the bandwidth/server load than have
realtime status updates.

The amount of bandwidth and server load that will be used by a
once-a-second query is probably pretty trivial (unless you're
expecting this to run over internet or dialup networks -- and even
then, it's probably not going to be worth worrying about). Even on an
old 10Mbit ethernet connection, a couple of extra packets every second
will not make a notable difference. This (IMO) is premature
optimization. :)
The status also updates whenever you send a command (like play/pause).

But does the server push events to the client? If there's a
filesystem error while a track is playing, how does your client know
about it? In addition, what happens if XMMS segfaults, or the server
machine loses power?
I'm really stuck on how to implement this now....

One of the big questions here is whether your client will have
exclusive access to the XMMS server. That is, will it be possible for
more than one such client to connect to the same XMMS, and/or for XMMS
to have direct interaction on its host machine?

If you have exclusive access, then changes in the status of XMMS will
only happen when 1) you change it yourself, or 2) there is an error.
In this case, you can check status much less often. (However, you'll
still want to deal with the error conditions, which probably means
checking at a much shorter interval than expected track length.) If,
on the other hand, there may be more than one client/user interacting
with XMMS, then you also have to deal with the possibility of your
server changing status without your client taking direct action.

I really think that you *do* want to do fairly frequent status checks
with your server. The cost is small, and the gains in responsiveness
and robustness are potentially very significant.

Jeff Shannon
 
S

Simon John

Jeff Shannon wrote:

[snip]
The amount of bandwidth and server load that will be used by a
once-a-second query is probably pretty trivial (unless you're
expecting this to run over internet or dialup networks -- and even
then, it's probably not going to be worth worrying about). Even on an
old 10Mbit ethernet connection, a couple of extra packets every second
will not make a notable difference. This (IMO) is premature
optimization. :)

It is designed to work over 802.11b (so under 11Mbit).

I'm going to fire up Ethereal later and see how much traffic this would
cause, most of the commands are only about 30bytes long, and the
longest response would be the filename, it just seems to me that
polling a server once every second or two, is kinda like a DDoS....

[...]
But does the server push events to the client? If there's a
filesystem error while a track is playing, how does your client know
about it? In addition, what happens if XMMS segfaults, or the server
machine loses power?

No, this is not server push, the client must query the server. Plus the
InetCtrl plugin does seem to segfault quite a lot, resulting in a
socket exception - I'll have to make sure that the client stops
querying the server after a socket excption, and doesn't keep trying
(resulting in lots of error dialogs!)

[...]
One of the big questions here is whether your client will have
exclusive access to the XMMS server. That is, will it be possible for
more than one such client to connect to the same XMMS, and/or for XMMS
to have direct interaction on its host machine?

No, you can have multiple connections to the server, and you can use
XMMS directly, so it would be possible for the client to miss events.

[...]
I really think that you *do* want to do fairly frequent status checks
with your server. The cost is small, and the gains in responsiveness
and robustness are potentially very significant.

Yes, I'm coming around to this POV too, but I still don't know how to
implement it (querying every 2 seconds say) in a multi-tasking manor -
as I said, sleep() hangs up the GUI, and alarm() is not portable....

Thanks for your suggestions.
 
S

Simon John

OK, I've implemented the 2sec threaded update, but I'm having some
problems with it.

Basically the thread will have to just run constantly, never exiting
(just sleeping for 2secs), which seems to work OK except when I try to
get the thread to do anything with the main program's window.

As the thread doesn't end, it doesn't return a result, so on every pass
of the thread's while loop, I write the current track info to the
mainWindow directly, however this causes the program to hang. Here is a
snippet of the current method:

class ThreadedInfo(Thread):
"""overloads init and defines run"""
def __init__(self):
Thread.__init__(self)

def run(self):
# runs the whole time
while 1:
self.info()
time.sleep(2)

def info(self):
"""referencing window kills linux here"""

# get track info, returned as dictionary
self.info_dict = backend.getInfo(config.server, config.port)

I was thinking of getting the thread to just run once, then getting the
main program to write the result (using join() ) to the mainWindow.
That method would be something like this, but it's almost totally
pointless using a thread then, as the while loop will singletask the
program:

while 1:
# start thread
self.infothread.start()

# when thread ends, get result
self.result = self.infothread.join()

# write result to window
window.mainTextarea.setText(self.result)

# pause for 2secs before starting again
sleep(2)

I made sure that I built PyQt using threads, so that's not the issue.
Any other ideas?
 
J

Jarek Zgoda

Simon John napisa³(a):
Damn, seems Qt GUI objects (windgets) aren't thread-safe:

http://doc.trolltech.com/3.3/threads.html#11

Like most (if not all) others GUI toolkits.
So I'm going to have to find a way of using a thread to fetch the data,
and then using the main program to update the GUI... Someone suggested
using events:

http://mail.python.org/pipermail/python-list/2002-February/089360.html

See http://www.informit.com/articles/printerfriendly.asp?p=30708
 
S

Simon John

Ah yes, that Informit article helped endlessly - I'm all done now - got
the backend to fetch the info from the server every 2secs using a
QThread, then it pass the data back to the GUI frontend by raising a
custom event!

Thanks for all the help folks, now I'm off to compile the new PyQt 3.14
;-)
 

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

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top