Colas
*****

**Código fuente:** Lib/asyncio/queue.py

======================================================================

Las colas asyncio son diseñadas para ser similares a clases del módulo
"queue".  Sin embargo las colas asyncio no son seguras para hilos, son
diseñadas para usar específicamente en código async/await.

Nota que los métodos de colas de asyncio no tienen un parámetro
*timeout*; usa la función "asyncio.wait_for()" para hacer operaciones
de cola con un tiempo de espera.

Ver también la sección Examples a continuación.


Cola
====

class asyncio.Queue(maxsize=0)

   Una cola primero en entrar, primero en salir (PEPS, o *FIFO* en
   inglés).

   Si *maxsize* es menor que o igual a cero, el tamaño de la cola es
   infinito.  Si es un entero mayor a "0", entonces "await put()" se
   bloquea cuando una cola alcanza su *maxsize* hasta que un elemento
   es removido por "get()".

   Diferente de los subprocesos de la biblioteca estándar "queue", el
   tamaño de la cola siempre es conocido y puede ser retornado
   llamando el método "qsize()".

   Distinto en la versión 3.10: Excluido el parámetro *loop*.

   Esta clase es no segura para hilos.

   maxsize

      Número de ítems permitidos en la cola.

   empty()

      Retorna "True" si la cola es vacía, o "False" en caso contrario.

   full()

      Retorna "True" si hay "maxsize" ítems en la cola.

      Si la cola fue inicializada con "maxsize=0" (el predeterminado),
      entonces "fill()" nunca retorna "True".

   coroutine get()

      Remueve y retorna un ítem de la cola. Si la cola es vacía,
      espera hasta que un ítem esté disponible.

   get_nowait()

      Retorna un ítem si uno está inmediatamente disponible, de otra
      manera levanta "QueueEmpty".

   coroutine join()

      Se bloquea hasta que todos los ítems en la cola han sido
      recibidos y procesados.

      El conteo de tareas no terminadas sube siempre que un ítem es
      agregado a la cola. El conteo baja siempre que la ejecución de
      una corrutina "task_done()" para indicar que el ítem fue
      recuperado y todo el trabajo en él está completo.  Cuando el
      conteo de tareas inacabadas llega a cero, "join()" se
      desbloquea.

   coroutine put(item)

      Pone un ítem en la cola. Si la cola está completa, espera hasta
      que una entrada vacía esté disponible antes de agregar el ítem.

   put_nowait(item)

      Pone un ítem en la cola sin bloquearse.

      Si no hay inmediatamente disponibles entradas vacías, lanza
      "QueueFull".

   qsize()

      Retorna el número de ítems en la cola.

   task_done()

      Indica que una tarea formalmente en cola está completa.

      Usada por consumidores de la cola. Para cada "get()" usado para
      buscar una tarea, una ejecución subsecuente a "task_done()" dice
      a la cola que el procesamiento de la tarea está completo.

      Si un "join()" está actualmente bloqueando, éste se resumirá
      cuando todos los ítems han sido procesados (implicado que un
      método "task_done()" fue recibido por cada ítem que ha sido
      "put()" en la cola.

      Lanza "ValueError" si fue llamado más veces que los ítems en la
      cola.


Cola de prioridad
=================

class asyncio.PriorityQueue

   Una variante de "Queue"; recupera entradas en su orden de prioridad
   (el más bajo primero).

   Las entradas son típicamente tuplas de la forma "(priority_number,
   data)".


Cola UEPA (o *LIFO* en inglés)
==============================

class asyncio.LifoQueue

   Una variante de una "Queue" que recupera primero el elemento
   agregado más reciente (último en entrar, primero en salir).


Excepciones
===========

exception asyncio.QueueEmpty

   Esta excepción es lanzada cuando el método "get_nowait()" es
   ejecutado en una cola vacía.

exception asyncio.QueueFull

   Las excepciones son lanzadas cuando el método "put_nowait()" es
   lanzado en una cola que ha alcanzado su *maxsize*.


Ejemplos
========

Las colas pueden ser usadas para distribuir cargas de trabajo entre
múltiples tareas concurrentes:

   import asyncio
   import random
   import time


   async def worker(name, queue):
       while True:
           # Get a "work item" out of the queue.
           sleep_for = await queue.get()

           # Sleep for the "sleep_for" seconds.
           await asyncio.sleep(sleep_for)

           # Notify the queue that the "work item" has been processed.
           queue.task_done()

           print(f'{name} has slept for {sleep_for:.2f} seconds')


   async def main():
       # Create a queue that we will use to store our "workload".
       queue = asyncio.Queue()

       # Generate random timings and put them into the queue.
       total_sleep_time = 0
       for _ in range(20):
           sleep_for = random.uniform(0.05, 1.0)
           total_sleep_time += sleep_for
           queue.put_nowait(sleep_for)

       # Create three worker tasks to process the queue concurrently.
       tasks = []
       for i in range(3):
           task = asyncio.create_task(worker(f'worker-{i}', queue))
           tasks.append(task)

       # Wait until the queue is fully processed.
       started_at = time.monotonic()
       await queue.join()
       total_slept_for = time.monotonic() - started_at

       # Cancel our worker tasks.
       for task in tasks:
           task.cancel()
       # Wait until all worker tasks are cancelled.
       await asyncio.gather(*tasks, return_exceptions=True)

       print('====')
       print(f'3 workers slept in parallel for {total_slept_for:.2f} seconds')
       print(f'total expected sleep time: {total_sleep_time:.2f} seconds')


   asyncio.run(main())
