2008-10-01 27 views
12

Tengo un hilo que escribe los resultados en una cola.Obtener todos los elementos del hilo Cola

En otro hilo (GUI), que periódicamente (en caso de reposo) verifique si hay resultados en la cola, así:

def queue_get_all(q): 
    items = [] 
    while 1: 
     try: 
      items.append(q.get_nowait()) 
     except Empty, e: 
      break 
    return items 

Es esta una buena manera de hacerlo?

Editar:

Lo digo porque a veces el subproceso en espera queda atascado durante unos segundos sin sacar nuevos resultados.

El problema "pegado" resultó ser porque yo estaba haciendo el procesamiento en el controlador de eventos de inactividad, sin asegurarse de que este tipo de eventos son en realidad generan llamando wx.WakeUpIdle, tal como se recomienda.

Respuesta

7

Estaría muy sorprendido si la llamada get_nowait() hizo la pausa por no volver si la lista estaba vacía.

¿Podría ser que está publicando una gran cantidad de elementos (¿quizás grandes?) Entre cheques, lo que significa que el hilo de recepción tiene una gran cantidad de datos para sacar del Queue? Usted podría intentar limitar el número de recuperar en un solo lote:

def queue_get_all(q): 
    items = [] 
    maxItemsToRetreive = 10 
    for numOfItemsRetrieved in range(0, maxItemsToRetreive): 
     try: 
      if numOfItemsRetrieved == maxItemsToRetreive: 
       break 
      items.append(q.get_nowait()) 
     except Empty, e: 
      break 
    return items 

Esto limitaría el hilo de recepción para tirar de hasta 10 elementos a la vez.

+0

Podría causar largas esperas si lo llama desde hace tiempo 1: busyloop. De ser así, el consumidor no solo estaría reduciendo el tiempo de espera del productor, sino que también pasaría mucho tiempo manteniendo el bloqueo de la cola, lo que podría bloquear al productor. (Esto es más probable si tiene múltiples hilos de consumo.) – Brian

+0

Buen punto Brian. Me dio la impresión de que eliben no llamaba a todo esto con frecuencia, pero podría estar equivocado, ¿vale? –

+0

Vaya, tiene razón, me perdí la parte de llamarlo en un evento inactivo. Eso no sería suficiente para causar tales problemas. – Brian

1

veo que está utilizando get_nowait(), que según la documentación, "volver [s] un artículo si uno está disponible de inmediato, de lo contrario elevar la excepción vacío"

Ahora, le sucede a salir de la bucle cuando se lanza una excepción vacía. Por lo tanto, si no hay resultados inmediatamente disponibles en la cola, su función devuelve una lista de elementos vacíos.

¿Hay alguna razón por la que no esté utilizando el método get()? Puede ser que el get_nowait() falle porque la cola está atendiendo una solicitud put() en ese mismo momento.

+1

No estoy usando get() porque no quiero bloquear la GUI. Está bien si la llamada piensa que no hay nada en la Q justo cuando se está poniendo un nuevo artículo, porque lo llamo periódicamente –

12

Si siempre está quitando todos los artículos disponibles de la cola, ¿hay algún punto real en el uso de una cola, en lugar de solo una lista con un candado? es decir:

from __future__ import with_statement 
import threading 

class ItemStore(object): 
    def __init__(self): 
     self.lock = threading.Lock() 
     self.items = [] 

    def add(self, item): 
     with self.lock: 
      self.items.append(item) 

    def getAll(self): 
     with self.lock: 
      items, self.items = self.items, [] 
     return items 

Si también está tirando de ellos de forma individual, y haciendo uso de la conducta de bloqueo para las colas vacías, se debe usar la cola, pero su caso de uso se ve mucho más simple, y podría ser mejor servido por la enfoque anterior.

[Edit2] me había perdido el hecho de que eres el sondeo de la cola de un bucle de inactividad, y de su actualización, veo que el problema no está relacionado con la contención, por lo que la aproximación por debajo de ISN' realmente relevante para su problema Lo dejé en caso de que alguien encuentre una variante de bloqueo de este útil:

Para los casos en los que desea bloquear hasta obtener al menos un resultado, puede modificar el código anterior para esperar que los datos estén disponibles a través de ser señalado por el hilo productor. P.ej.

class ItemStore(object): 
    def __init__(self): 
     self.cond = threading.Condition() 
     self.items = [] 

    def add(self, item): 
     with self.cond: 
      self.items.append(item) 
      self.cond.notify() # Wake 1 thread waiting on cond (if any) 

    def getAll(self, blocking=False): 
     with self.cond: 
      # If blocking is true, always return at least 1 item 
      while blocking and len(self.items) == 0: 
       self.cond.wait() 
      items, self.items = self.items, [] 
     return items 
5

Creo que la forma más fácil de conseguir todos los elementos de la fila es el siguiente:

def get_all_queue_result(queue): 

    result_list = [] 
    while not queue.empty(): 
     result_list.append(queue.get()) 

    return result_list 
+1

Esto todavía podría darle una excepción en algún momento. Desde los documentos: si empty() devuelve True, no garantiza que una llamada posterior a put() no se bloquee. Del mismo modo, si empty() devuelve False, no garantiza que una llamada posterior a get() no se bloquee. https://docs.python.org/2/library/queue.html – fantabolous

0

Si haya terminado de escribir a la cola, qsize debe hacer el truco sin necesidad de comprobar la cola de cada iteración.

responseList = [] 
for items in range(0, q.qsize()): 
    responseList.append(q.get_nowait()) 
+0

'qsize' es similar a' empty', ya que no está garantizado. De los documentos: devuelve el tamaño aproximado de la cola. Tenga en cuenta que qsize()> 0 no garantiza que un get() posterior no bloqueará, ni qsize() fantabolous

Cuestiones relacionadas