Concurrencia y paralelismo con Python para seres humanos

Abstract

Aprendé cómo (y cuándo) usar multithreading y multiprocessing en Python de manera efectiva, tratando de evitar los errores más comunes. Una breve reseña sobre concurrencia en general y los módulos más comunes: concurrent.futures, multiprocessing, subprocess y threading.

Description

En Python la concurrencia es un tema bastante complicado. Si alguna vez te pasó que quisiste paralelizar alguna tarea sencilla, seguro que te acordarás del stress que te causó. La primer pregunta es: ¿qué módulo usar? En Python hay 4 librerías principales para concurrencia y paralelismo: * dos de bajo nivel (threading y subprocess) y, * dos de más alto nivel (multiprocessing y concurrent.futures).

A su vez, cPython tiene el problema del GIL, que es una limitante para multithreading. Pero el GIL solo afecta tareas que son "CPU intensive", lo cual es raro, así que si tienes tareas I/O bound (lo más común), el GIL no significa un verdadero problema, y se puede usar multithreading, que es más "liviano" que multiprocessing.

Una vez que decidiste qué modelo usar (threading or concurrency), y qué paquete usar (multiprocessing, concurrent.futures, etc), arranca el problema de sincronizar datos. Si usas multithreading, hay problemas de race condition con variables globales. Si usás multiprocessing, hay problema de shared memory (que recién va a existir en Python 3.8!) 😱.

En fin, la concurrencia y el paralelismo es un tema apasionante, pero puede ser complicado.

El objetivo de esta charla es resumir los conceptos relacionados, los modelos y sus limitantes, y las buenas prácticas para tener un modelo concurrente/paralelo y no perder la cabeza en el intento.