Joyitas en la stdlib: concurrent.futures

El módulo que vamos a ver, concurrent.futures, tiene una funcionalidad limitada. Trata de introducir una capa de simplificación sobre los módulos threading y multiprocessing.
Solo disponible en Python 3!!!!
Según la documentación oficial, el módulo proporciona una interfaz de alto nivel para ejecutar callables (¿invocables?) de forma asíncrona. Por su parte, según la Wikipedia, los futuros (no vamos a hablar de bolsa ni de especulación), en Programación, son un reemplazo para un resultado que todavía no está disponible, generalmente debido a que su cómputo todavía no ha terminado, o su transferencia por la red no se ha completado. El término futures también lo podéis encontrar como promises, delay, deferred,… En general, independientemente de cómo lo queráis llamar, lo podéis ver como un resultado pendiente.
El módulo posee una base abstracta, Executor, que se usa para las subclases ThreadPoolExecutor y ProcessPoolExecutor que, si sois un poco deductivos, sirven para usar multihilo (threading) o multiproceso (multiprocessing) por debajo, respectivamente.
Veamos un ejemplo de la primera subclase, ThreadPoolExecutor, con un caso práctico que hice el otro día. Tenía que descargar cosas y lo quise hacer asíncrono, es un ejemplo muy típico, pero, además, quisé mostrar en pantalla un mensaje dinámico para que se viese que el programa estaba ‘haciendo algo’ y que no se había quedado ‘tostado’. Pongamos el ejemplo y luego lo comentamos y vemos el resultado:

Si ejecutáis el anterior código en una terminal, yo lo he llamado temp.py, podéis ver el efecto que andaba buscando:

Vamos a comentar la función tareas un poco más en detalle.

  1. Dentro de esa función he escrito otra que se llama get_pic. Esa función lo único que hace es descargar la información bruta de las imágenes. Las imágenes no las vamos a guardar en nuestro disco duro ya que no es necesario.
  2. Luego vamos a crear msg y ciclo que serán el mensaje que mostraremos en pantalla. ciclo es un iterador infinito.
  3. Más tarde instanciamos ThreadPoolExecutor y creamos una lista, ex, donde guardar los ‘futuros’. Los objetos instanciados de la clase Future (cada uno de los elementos de la lista ex) encapsulan la ejecución asíncrona del callable (‘invocable’). Cada uno de estos objetos provienen de Executor.submit().
  4. Dentro del bloque while le preguntamos a cada una de las tareas si han terminado usando el método Future.done(). Si ha terminado nos devolverá True o, en caso contrario, nos devolverá False. Como quiero mostrar el mensaje de la imagen de más arriba mientras no hayan terminado todas las descargas en el bucle exijo que todas hayan terminado usando la función builtin all.
  5. Y, por último, devuelvo la lista con los ‘futuros’.

En la función tareas podéis definir el número de workers a usar.
Si hacéis un print de raw_data, lo que devuelve la llamada a tareas, veréis que es algo parecido a lo siguiente:

Si queréis la información bruta de una de las descargas podéis usar el método Future.result(). Si, además, volvéis a llamar al método Future.done() veréis ahora que os devuelve True, ya que está terminada la tarea.:

Espero que la mini introducción os haya resultado de utilidad y de interés. Como siempre, si veis alguna incorrección, falta de ortografía,…, avisadnos en los comentarios.

2 pensamientos sobre “Joyitas en la stdlib: concurrent.futures”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

84 − seventy six =