2008-10-17 12 views
12

Pareceteclado cola de bloqueo interrumpible en Python

import Queue 

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

es interrumpible teclado (Ctrl-C), mientras que

import Queue 

Queue.Queue().get() 

no lo es. Siempre podría crear un bucle;

import Queue 
q = Queue() 

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

pero esto parece una cosa extraña de hacer.

Entonces, ¿hay alguna manera de obtener un indefinidamente esperando pero el teclado es interrumpible Queue.get()?

+0

¿Se puede interrumpir el hilo de otra forma? – fatuhoku

+3

Este es [Error 1360] (http://bugs.python.org/issue1360) que se cerró como "no se corregirá". La solución sugerida es especificar siempre un tiempo de espera si necesita una interrupción. – dimo414

Respuesta

6

Queue objetos tienen este comportamiento, ya que bloquean el uso de Condition objetos forman el módulo threading. Entonces, tu solución es realmente la única manera de hacerlo.

Sin embargo, si realmente quiere un método Queue que hace esto, puede monopatchear la clase Queue. Por ejemplo:

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

Esto le permitiría decir

q.interruptable_get() 

en lugar de

interruptable_get(q) 

aunque monkeypatching Normalmente se desaconseja por la comunidad Python en casos como estos, ya que una función regular parece igual de bueno.

+0

Ah, ya veo, un caso grave de abstracciones con fugas *. Ah bueno. * http://www.joelonsoftware.com/articles/LeakyAbstractions.html –

+0

¿Por qué no la subclase Queue, en lugar de parche mono? –

+0

El parche de mono es mejor cuando recibe objetos Queue que fueron instanciados y devueltos por un código de terceros que no puede cambiar, o posiblemente por un código de compañero de trabajo que tampoco puede cambiar. Sin embargo, quizás debería haber usado subclases, ya que probablemente no sea muy común. –

4

Esto puede no aplicarse en absoluto a su caso de uso. Pero he utilizado con éxito este patrón en varios casos: (impreciso y probablemente con errores, pero entiendes el punto).

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() 
Cuestiones relacionadas