Concurrencia en Python - Introducción

En este capítulo, comprenderemos el concepto de concurrencia en Python y aprenderemos sobre los diferentes hilos y procesos.

¿Qué es la concurrencia?

En palabras simples, la concurrencia es la ocurrencia de dos o más eventos al mismo tiempo. La concurrencia es un fenómeno natural porque muchos eventos ocurren simultáneamente en un momento dado.

En términos de programación, la concurrencia es cuando dos tareas se superponen en la ejecución. Con la programación concurrente, el rendimiento de nuestras aplicaciones y sistemas de software se puede mejorar porque podemos tratar simultáneamente las solicitudes en lugar de esperar a que se complete una anterior.

Revisión histórica de concurrencia

Los siguientes puntos nos darán una breve revisión histórica de la concurrencia:

Del concepto de ferrocarriles

La concurrencia está estrechamente relacionada con el concepto de ferrocarriles. Con los ferrocarriles, existía la necesidad de manejar múltiples trenes en el mismo sistema ferroviario de tal manera que cada tren llegara a su destino de manera segura.

Computación concurrente en la academia

El interés por la concurrencia de las ciencias de la computación comenzó con el trabajo de investigación publicado por Edsger W. Dijkstra en 1965. En este trabajo, identificó y resolvió el problema de la exclusión mutua, la propiedad del control de concurrencia.

Primitivas de simultaneidad de alto nivel

En los últimos tiempos, los programadores están obteniendo soluciones concurrentes mejoradas debido a la introducción de primitivas de concurrencia de alto nivel.

Simultaneidad mejorada con lenguajes de programación

Los lenguajes de programación como Golang, Rust y Python de Google han realizado desarrollos increíbles en áreas que nos ayudan a obtener mejores soluciones concurrentes.

¿Qué son hilos y subprocesos múltiples?

Threades la unidad de ejecución más pequeña que se puede realizar en un sistema operativo. No es un programa en sí mismo, sino que se ejecuta dentro de un programa. En otras palabras, los hilos no son independientes entre sí. Cada hilo comparte sección de código, sección de datos, etc. con otros hilos. También se conocen como procesos ligeros.

Un hilo consta de los siguientes componentes:

  • Contador de programa que consta de la dirección de la siguiente instrucción ejecutable

  • Stack

  • Conjunto de registros

  • Una identificación única

Multithreading, por otro lado, es la capacidad de una CPU para administrar el uso del sistema operativo ejecutando múltiples subprocesos al mismo tiempo. La idea principal del subproceso múltiple es lograr el paralelismo dividiendo un proceso en varios subprocesos. El concepto de multiproceso se puede entender con la ayuda del siguiente ejemplo.

Ejemplo

Supongamos que estamos ejecutando un proceso en particular en el que abrimos MS Word para escribir contenido en él. Se asignará un hilo para abrir MS Word y se requerirá otro hilo para escribir contenido en él. Y ahora, si queremos editar el existente, se requerirá otro hilo para realizar la tarea de edición y así sucesivamente.

¿Qué es proceso y multiprocesamiento?

UNAprocessse define como una entidad, que representa la unidad básica de trabajo a implementar en el sistema. Para decirlo en términos simples, escribimos nuestros programas de computadora en un archivo de texto y cuando ejecutamos este programa, se convierte en un proceso que realiza todas las tareas mencionadas en el programa. Durante el ciclo de vida del proceso, pasa por diferentes etapas: Inicio, Listo, Ejecución, Espera y Terminación.

El siguiente diagrama muestra las diferentes etapas de un proceso:

Un proceso puede tener solo un hilo, llamado hilo principal, o varios hilos que tengan su propio conjunto de registros, contador de programa y pila. El siguiente diagrama nos mostrará la diferencia:

Multiprocessing,por otro lado, es el uso de dos o más CPU dentro de un solo sistema informático. Nuestro objetivo principal es aprovechar todo el potencial de nuestro hardware. Para lograr esto, necesitamos utilizar el número total de núcleos de CPU disponibles en nuestro sistema informático. El multiprocesamiento es el mejor enfoque para hacerlo.

Python es uno de los lenguajes de programación más populares. Las siguientes son algunas de las razones que lo hacen adecuado para aplicaciones concurrentes:

Azúcar sintáctica

El azúcar sintáctico es una sintaxis dentro de un lenguaje de programación que está diseñado para facilitar la lectura o la expresión. Hace que el lenguaje sea más "dulce" para el uso humano: las cosas se pueden expresar de forma más clara, más concisa o en un estilo alternativo basado en las preferencias. Python viene con métodos Magic, que se pueden definir para actuar sobre objetos. Estos métodos mágicos se utilizan como azúcar sintáctico y están vinculados a palabras clave más fáciles de entender.

Comunidad grande

El lenguaje Python ha sido testigo de una tasa de adopción masiva entre científicos de datos y matemáticos, que trabajan en el campo de la inteligencia artificial, el aprendizaje automático, el aprendizaje profundo y el análisis cuantitativo.

API útiles para programación concurrente

Python 2 y 3 tienen una gran cantidad de API dedicadas para la programación paralela / concurrente. Los más populares de ellos sonthreading, concurrent.features, multiprocessing, asyncio, gevent and greenlets, etc.

Limitaciones de Python en la implementación de aplicaciones concurrentes

Python viene con una limitación para aplicaciones concurrentes. Esta limitación se llamaGIL (Global Interpreter Lock)está presente en Python. GIL nunca nos permite utilizar múltiples núcleos de CPU y, por lo tanto, podemos decir que no hay verdaderos hilos en Python. Podemos entender el concepto de GIL de la siguiente manera:

GIL (bloqueo de intérprete global)

Es uno de los temas más controvertidos del mundo de Python. En CPython, GIL es el mutex, el bloqueo de exclusión mutua, que hace que las cosas sean seguras para los subprocesos. En otras palabras, podemos decir que GIL evita que varios subprocesos ejecuten código Python en paralelo. El bloqueo puede ser retenido por un solo hilo a la vez y si queremos ejecutar un hilo, primero debe adquirir el bloqueo. El diagrama que se muestra a continuación le ayudará a comprender el funcionamiento de GIL.

Sin embargo, existen algunas bibliotecas e implementaciones en Python como Numpy, Jpython y IronPytbhon. Estas bibliotecas funcionan sin ninguna interacción con GIL.