[Tutor] Python performance resources & resouce usage hints

Kent Johnson kent37 at tds.net
Fri Apr 7 18:10:37 CEST 2006


Liam Clarke wrote:
> Hi,
> 
> I've developed what would be my largest Python app to date. And, going
> from the crude Windows Task Manager, it's trying to use as much CPU
> time as it can get when it's idle.
> 
> This, no doub,t is due to my design.
> 
> I have an UDP socket server, a packet cruncher, and a DAO.
> Each resides in it's own thread, and each thread is connected to the
> next by a Queue.
> 
> So it's server ---> cruncher --> DAO.
> 
> Each thread's run() method basically looks like this -
> 
>         while True:
>             try:
>                 data = self.queue.get(False)
>                 self.DAO.send_data(data)
>             except Empty:
>                 if self.shutdown:
>                     print "\DAO closing"
>                     return
>                 continue
> 
> 
> i.e. each thread is looping endlessly until data arrives via the
> queue. I can't believe it chews the CPU time the way it does, but I
> suppose it's easy to do so.

Yes, it's easy. You have basically told the thread to check the queue as 
often as possible. So it is running as fast as it can, checking the 
queue and handling whatever comes its way.
> 
> My query to the list is twofold -
> 
> First, if anyone knows of any websites with articles on Python
> threading optimisation/pitfalls websites, I'd be greatly appreciative.

There's not much. This might help:
http://linuxgazette.net/107/pai.html

This book is excellent for teaching some of the tools that are used for 
communication and synchronization between threads:
http://greenteapress.com/semaphores/

There are many threading related recipes in the Python Cookbook, both 
online and printed.
http://aspn.activestate.com/ASPN/Cookbook/Python

> Okay, the 2nd piece of advice I'm seeking, is what would be the most
> efficient path here?
> My initial thoughts are along three lines:
> 
> Either:
> 
> A) Increase the queue size of the socket servers

I don't see how that would help.

> B) Use timer threads to 'pulse' my threads.

That's a lot of additional complexity.
> A) Increase the queue size of the socket servers
> B) Use blocking queues
> 
> Or:
> 
> A) Use blocking queues with a timeout
> B) Use the socket servers to "wake" processing threads

These are all better.
> 
> As Python doesn't have sleeping threads etc, the third option is my
> current measure of last resort, as there'll be some substantial
> rejigging, and I'm not overly experienced with threads.

Use time.sleep() to sleep a thread.

The simplest fix is to add a time.sleep() into your loops. Then the 
thread will check the queue, process any work, and sleep for a little 
while. (This is called a busy loop.)

The disadvantage of this solution is that there is a trade off between 
CPU usage and responsiveness. If the sleep is very short, the thread 
will be very responsive but it will still run a lot and use CPU when 
idling. If you make the timeout long, the idle CPU will be very low but 
responsiveness will be poor.

If you can live with a response delay of 0.05 or 0.1 second, try that, 
it should cut the CPU usage dramatically. Even a 0.01 delay might make a 
big difference.


A better fix is to use blocking queues or other blocking events. In this 
approach, a thread will block until there is something to do, then wake 
up, do its work and go back to sleep.

The hitch here is you need to find another way to signal the thread to 
exit. One possibility is just to mark them as daemon threads, then they 
will exit when your app exits. This is a very simple solution if you 
don't have any cleanup actions you want to do in the threads.

Another possibility might be to send a "quit" message in the queue. When 
the thread sees the special quit message, it forwards it to the next 
thread and exits.

If neither of these work then you could use a queue.get() with a timeout 
so you check the done flag periodically.

Kent



More information about the Tutor mailing list