False Queue.Empty exception ?

Tim Peters tim.one at comcast.net
Mon Jun 10 23:02:49 CEST 2002

[Scott Blomquist]
> I use the Queue class to maintain a threadpool of threads which
> currently have no task, rather than creating/reaping threads as they
> are needed. When I have a task, I grab one out of the queue and assign
> the task to it. To add complexity :) I have made the threadpool able
> to have a min and a max number of threads created, and if the queue of
> free threads is Empty, then I (potentially) create more threads (up to
> the max), and drop them into the free queue.
> The problem is that the Empty exception appears to be raised even when
> the queue is in fact not empty - causing me to create threads when I
> don't really need to - some sort of race condition in the following
> code from the Queue class?
> ... [code snipped] ...
> Keeping in mind that I am doing a non-blocking get, it seems as though
> if there is a thread between the self.esema.acquire(0) and the
> self.esema.release(), and it gets switched out and another thread is
> switched in and comes through the get call, it will fail on the
> self.esema.acquire(0), even though the queue is not neccessarily
> emtpy.

Yes.  As the docs say,

    Exception raised when non-blocking get() (or get_nowait()) is called
    on a Queue object which is empty or locked.

A non-blocking get() can't know for sure whether the queue is empty if
someone else is holding the esema lock, and can't wait for that lock (so
that it *could* know for sure) without blocking.  Hence it does what it's
documented to do, raising Empty either if it knows for sure *or* can't make
progress without blocking.  It doesn't even know which is the case -- that
esema can't be acquired instantly is equally true of both cases, and is the
only clue it has.

This is adequate for most apps, which use an unbounded or fixed-size queue,
and simply loop on Empty or Full, perhaps with a short time.sleep() in

Note that even if you did know for sure that the queue was Empty, you could
still create needless threads:  there's nothing to stop all the threads in
use from returning to the queue between the time you learn it was empty and
the time you get around to creating a new thread.

But threads are cheap.  Stick as many in the pool as you think you can
reasonably use at one time, and save yourself the bother of trying to adjust
that number.

it's-not-going-to-work-right-anyway<wink>-ly y'rs  - tim

More information about the Python-list mailing list