views:

408

answers:

2

Hi!

It seems

import Queue

Queue.Queue().get(timeout=10)

is keyboard interruptible (ctrl-c) whereas

import Queue

Queue.Queue().get()

is not. I could always create a loop;

import Queue
q = Queue()

while True:
    try:
        q.get(timeout=1000)
    except Queue.Empty:
        pass

but this seems like a strange thing to do.

So, is there a way of getting an indefinitely waiting but keyboard interruptible Queue.get()?

+3  A: 

Queue objects have this behavior because they lock using Condition objects form the threading module. So your solution is really the only way to go.

However, if you really want a Queue method that does this, you can monkeypatch the Queue class. For example:

def interruptable_get(self):
    while True:
        try:
            return self.get(timeout=1000)
        except Queue.Empty:
            pass
Queue.interruptable_get = interruptable_get

This would let you say

q.interruptable_get()

instead of

interruptable_get(q)

although monkeypatching is generally discouraged by the Python community in cases such as these, since a regular function seems just as good.

Eli Courtwright
Ah, I see, a bad case of leaky abstractions*. Ahwell.* http://www.joelonsoftware.com/articles/LeakyAbstractions.html
Henrik Gustafsson
Why not subclass Queue, rather than monkey patching it?
fivebells
Monkeypatching is better when you're receiving Queue objects that were instantiated and returned by some third-party code that you can't change, or possibly by some co-worker's code that you also can't change. However, perhaps I should have used subclassing since that's probably not very common.
Eli Courtwright
+3  A: 

This may not apply to your use case at all. But I've successfully used this pattern in several cases: (sketchy and likely buggy, but you get the point).

STOP = object()

def consumer(q):
    while True:
        x = q.get()
        if x is STOP:
            return
        consume(x)

def main()
    q = Queue()
    c=threading.Thread(target=consumer,args=[q])

    try:
        run_producer(q)
    except KeybordInterrupt:
        q.enqueue(STOP)
    c.join()
Anders Waldenborg