====== Introducción ====== * [[https://realpython.com/intro-to-python-threading/|An Intro to Threading in Python]] Básicamente hay dos tipos de programas en los que puede interesar la concurrencia: * CPU-Bound: aplicaciones intensivas en CPU. Pierden tiempo porque podrían aprovechar todos los núcleos de la máquina. * IO-Bound: aplicaciones que no son intensivas en CPU, pero que pierden tiempo esperando por resultados externos en los que podrían seguir haciendo cosas. Como vamos a estar siempre limitados por el GIL, sólo va a haber un hilo ejecutándose en cada //intérprete// de Python (suele conincidir con un proceso, ver [[https://medium.com/hackernoon/has-the-python-gil-been-slain-9440d28fa93d|Has the Python GIL been slain?]] para más detalles). Para aplicaciones IO-Bound nos vale perfectamente ''threading'' (es cooperativo, no preemptivo), ya que cuando una aplicación no hace nada porque está esperando a un resultado de IO, deja que se ejecute otra tarea. Para aplicaciones CPU-Bound, hay que usar ''multiprocessing'', pero también son útiles si el programa tiene alguna parte IO-Bound. El precio a pagar es que el inicio de un proceso y las comunicaciones entre ellos son más pesadas que en el caso de los hilos. Los intérpretes vendrían a estar en el medio. ===== Términos clave ===== * Operación atómica: conjunto de operaciones que se pueden realizar sin que ocurra un cambio de contexto (el OS salta a otro proceso) * Sección crítica: sección de código en la que un proceso solicita acceso a recursos compartidos. No se debería ejecutar a la vez en varios procesos * Deadlock: situación en la que dos o más procesos necesitan dos (o más) recursos para continuar y cada proceso posee uno. * Livelock: situación en la que dos o más procesos cambian continuamente de estado en respuesta a los cambios de estados de otros procesos * mutex: semáforo binario o lock que activa un proceso para que ese recurso no pueda ser accedido por ningún otro * Condición de carrera: situación en la que los procesos compiten por acceder a un recurso compartido y el estado del programa depende de qué proceso gane la carrera * Starvation: en general, situación en la que un procesos se queda sin trabajo que hacer. Se usa sobre todo cuando un proceso no se llega a ejecutar a pesar de estar siempre preparado: puede ocurrir si 2 procesos se alternan indefinidamente ===== Semáforos ===== ===== Productor/Consumidor ===== * [[https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem|Producer–consumer problem]] ===== Lectores/Escritores ===== * [[https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem]] ===== La cena de los filósofos ===== * [[https://en.wikipedia.org/wiki/Dining_philosophers_problem]] ===== Deadlock ===== - mutex - no preemptivo - hold and wait (un proceso sólo libera recursos cuando adquiere todos los necesarios para seguir ejecutándose) - Espera circular (A quiere R1, R2 y tiene R1, B también quiere R1, R2 y tiene R2 -> Generalizado a n procesos) ====== Sistemas distribuidos y sincronización ====== ===== Lamport timestamps ===== ===== Vector clocks ===== ===== Vector versions ===== ====== Peligros ====== * [[https://codewithoutrules.com/2017/08/16/concurrency-python/|The tragic tale of the deadlocking Python queue]] * [[https://pythonspeed.com/articles/python-multiprocessing/|Why your multiprocessing Pool is stuck (it’s full of sharks!)]] * [[https://docs.python.org/3/library/multiprocessing.html#programming-guidelines|multiprocessing programming guidelines]]