Colas con el módulo queue

Introducción

El módulo estándar Queue o queue (Python 2 o 3, respectivamente) permite crear y trabajar con colas de manera sencilla. Es generalmente utilizado en programas multi-hilo, ya que provee una forma de intercambiar información entre threads de manera segura.

Implementa tres tipos de colas, que difieren únicamente en el orden en que se retornan los ítems:

  • FIFO (primero en entrar primero en salir, del inglés «First In First Out»): el primer ítem que es añadido a la lista es el primero en ser retornado.
  • LIFO (último en entrar primero en salir, del inglés «Last In First Out»): el último ítem que es añadido a la lista es el primero en ser retornado.
  • Priority Queue (cola de prioridad): el ítem de menor valor es el primero en ser retornado.

Por lo tanto, cuenta con cinco clases: tres constructores (Queue, LifoQueue y PriorityQueue) junto con dos excepciones (Empty y Full).

Los tres constructores toman como único parámetro opcional maxsize, un entero que indica el límite de ítems en la cola. En caso de ser negativo o no indicarse, el tamaño de la cola es infinito.

Funciones

Todas las colas cuentan con 9 métodos públicos. A continuación, una breve descripción de cada uno. Véase la documentación del módulo para una información detallada.

  • qsize(): retorna el tamaño aproximado de la cola.
  •  

  • empty(): retorna True si la cola se encuentra vacía; False de lo contrario.
  •  

  • full(): retorna True si la cola se encuentra llena; Falso de lo contrario.
  •  

  • put(item, block=True, timeout=None): inserta item en la cola. Si block es True, timeout es None y la cola está llena, la función espera a que se libere un espacio para poder hacerlo. Si timeout es un número positivo, la función espera hasta dicho número en segundos y lanza la excepción Full si un espacio no se liberó en el lapso de tiempo. Si block es False, inserta item si inmediatamente hay un espacio libre; de lo contrario, lanza Full.
  •  

  • put_nowait(item): equivalente a put(item, False).
  •  

  • get(block=True, timeout=None): remueve y retorna un ítem de la cola. Si block es True, timeout es None y la cola está vacía, la función espera a que haya un ítem disponible. Si timeout es un número positivo, la función espera hasta dicho número en segundos y lanza la excepción Empty si no se encontró un ítem disponible en el lapso de tiempo. Si block es False, retorna un ítem si se encuentra inmediatamente disponible; de lo contrario, lanza Empty.
  •  

  • get_nowait(): equivalente a get(False).
  •  

  • task_done(): indica que una tarea de la cola se ha completado.
  •  

  • join(): bloquea la ejecución hasta que todos los ítems en la cola se hayan obtenido.

Los últimos dos métodos fueron añadidos en la versión 2.5 para el soporte de múltiples hilos.

Excepciones

La excepción Empty es lanzada cuando se llama a get(False) o get_nowait() en una cola que se encuentra vacía. Análogamente, Full es lanzada cuando se llama a put(item, False) o put_nowait(item) en una cola que ha alcanzado el número máximo de ítems (maxsize).

Priority Queue

En las colas de prioridad los ítems generalmente se insertan como una tupla, a diferencia de las FIFO y LIFO, indicando el número en el primer lugar y los datos en el segundo. Por ejemplo:

(5, "Perro")
(10, "Gato")
(1, "Conejo")

Aplicados a una cola de este tipo serían retornados en el orden:

(1, 'Conejo')
(5, 'Perro')
(10, 'Gato')

Ya que el primer valor de la tupla indica su prioridad. Los ítems con menor prioridad serán los primeros en ser retornados.

Ejemplos

Ejemplo 1

Añadir y retornar tres ítems. Nótese el orden en el que se obtienen, variando según el tipo de cola.

try:
    import Queue as queue
except ImportError:
    # Python 3
    import queue


fifo_queue = queue.Queue(3)
lifo_queue = queue.LifoQueue(3)
priority_queue = queue.PriorityQueue(3)

fifo_queue.put("Perro")
fifo_queue.put("Gato")
fifo_queue.put("Conejo")

lifo_queue.put("Perro")
lifo_queue.put("Gato")
lifo_queue.put("Conejo")

priority_queue.put((2, "Perro"))
priority_queue.put((3, "Gato"))
priority_queue.put((1, "Conejo"))

print("Cola FIFO")
print(fifo_queue.get())
print(fifo_queue.get())
print(fifo_queue.get())

print("\nCola LIFO")
print(lifo_queue.get())
print(lifo_queue.get())
print(lifo_queue.get())

print("\nCola de prioridad")
print(priority_queue.get())
print(priority_queue.get())
print(priority_queue.get())

Imprime:

Cola FIFO
Perro
Gato
Conejo

Cola LIFO
Conejo
Gato
Perro

Cola de prioridad
(1, 'Conejo')
(2, 'Perro')
(3, 'Gato')

O una solución más óptima:

for cur_queue in (fifo_queue, lifo_queue, priority_queue):
    print("")
    print(cur_queue)
    for i in range(3):
        print(cur_queue.get())

Si se desconociera la cantidad de ítems, podría utilizarse:

for cur_queue in (fifo_queue, lifo_queue, priority_queue):
    print("")
    print(cur_queue)
    while True:
        try:
            item = cur_queue.get_nowait()
        except queue.Empty:
            # Ya se han retornado todos los ítems
            break
        else:
            print(item)

Ejemplo 2

Cómo esperar a que las tareas de la cola se completen (extraído de la documentación):

def worker():
    while True:
        item = q.get()
        do_work(item)
        q.task_done()

q = Queue()
for i in range(num_worker_threads):
     t = Thread(target=worker)
     t.daemon = True
     t.start()

for item in source():
    q.put(item)

q.join()       # bloquear hasta que se completen las tareas

Versión

Python 2, Python 3



Deja una respuesta