significado multiprocesamiento python gil

python - multiprocesamiento - gil significado



¿Qué es un bloqueo de intérprete global(GIL)? (12)

Aquí hay algunos códigos que demuestran los efectos de GIL: https://github.com/cankav/python_gil_demonstration

¿Qué es un bloqueo de intérprete global y por qué es un problema?

Se ha hecho mucho ruido para eliminar el GIL de Python, y me gustaría entender por qué es tan importante. Nunca he escrito un compilador ni un intérprete, así que no seas frugal con los detalles, probablemente los necesite para que entiendan.



Cuando dos subprocesos tienen acceso a la misma variable, tienes un problema. En C ++, por ejemplo, la forma de evitar el problema es definir algún bloqueo mutex para evitar que dos subprocesos, por ejemplo, ingresen el setter de un objeto al mismo tiempo.

Multithreading es posible en python, pero dos hilos no se pueden ejecutar al mismo tiempo en una granularidad más fina que una instrucción de Python. El hilo de ejecución está obteniendo un bloqueo global llamado GIL.

Esto significa que si comienzas a escribir un código multiproceso para aprovechar tu procesador multinúcleo, tu rendimiento no mejorará. La solución habitual consiste en ir multiproceso.

Tenga en cuenta que es posible liberar el GIL si está dentro de un método que escribió en C, por ejemplo.

El uso de un GIL no es inherente a Python, sino a algunos de sus intérpretes, incluido el CPython más común. (#edited, ver comentario)

El problema de GIL sigue siendo válido en Python 3000.



Primero, comprendamos qué proporciona el pitón GIL:

Cualquier operación / instrucción se ejecuta en el intérprete. GIL garantiza que el intérprete se mantenga en un único hilo en un instante particular . Y su programa python con múltiples hilos funciona en un solo intérprete. En un instante particular, este intérprete está en un solo hilo. Significa que solo el hilo que contiene el intérprete se está ejecutando en cualquier instante .

Ahora, ¿por qué es eso un problema?

Su máquina podría tener múltiples núcleos / procesadores. Y los núcleos múltiples permiten que varios hilos se ejecuten simultáneamente, es decir, múltiples hilos pueden ejecutarse en cualquier instante particular. . Pero dado que el intérprete está en un único hilo, otros hilos no están haciendo nada a pesar de que tienen acceso a un núcleo. Por lo tanto, no obtiene ninguna ventaja de múltiples núcleos porque en un instante solo se está utilizando un único núcleo, que es el núcleo que utiliza el hilo que actualmente contiene el intérprete. Por lo tanto, su programa tardará tanto tiempo en ejecutarse como si se tratara de un único programa de subprocesos.

Sin embargo, las operaciones potencialmente bloqueantes o de larga ejecución, como E / S, procesamiento de imágenes y crujido de números NumPy, ocurren fuera del GIL. Tomado de here . Por lo tanto, para tales operaciones, una operación multiproceso será aún más rápida que una única operación con subprocesos a pesar de la presencia de GIL. Entonces, GIL no siempre es un cuello de botella.

Editar: GIL es un detalle de implementación de CPython. PyPy y Jython no tienen GIL, por lo que un programa verdaderamente multiproceso debería ser posible en ellos, pensó que nunca había usado PyPy y Jython y no estaba seguro de esto.


Python no permite multi-threading en el verdadero sentido de la palabra. Tiene un paquete de subprocesos múltiples, pero si desea multiproceso para acelerar su código, generalmente no es una buena idea usarlo. Python tiene una construcción llamada Global Interpreter Lock (GIL). GIL se asegura de que solo uno de tus ''hilos'' se pueda ejecutar en cualquier momento. Un hilo adquiere el GIL, hace un poco de trabajo, luego pasa el GIL al siguiente hilo. Esto sucede muy rápidamente, así que para el ojo humano puede parecer que tus hilos se están ejecutando en paralelo, pero en realidad solo están tomando turnos utilizando el mismo núcleo de CPU. Todo este pase de GIL agrega sobrecarga a la ejecución. Esto significa que si desea hacer que su código se ejecute más rápido, el uso del paquete de subprocesos a menudo no es una buena idea.

Hay razones para usar el paquete de enhebrado de Python. Si desea ejecutar algunas cosas al mismo tiempo, y la eficiencia no es una preocupación, entonces es totalmente bueno y conveniente. O si está ejecutando código que necesita esperar algo (como un IO), entonces podría tener mucho sentido. Pero la biblioteca de threading no le permitirá usar núcleos de CPU adicionales.

Multi-threading se puede subcontratar al sistema operativo (haciendo multiprocesamiento), alguna aplicación externa que llame a su código Python (por ejemplo, Spark o Hadoop), o algún código que llame su código Python (por ej .: podría tener su Python llamar a un código de una función C que hace las caras cosas de subprocesos múltiples).


Python''s GIL está destinado a serializar el acceso a las partes internas del intérprete desde diferentes hilos. En sistemas multi-core, significa que múltiples hilos no pueden hacer uso de múltiples núcleos de manera efectiva. (Si el GIL no condujo a este problema, a la mayoría de las personas no les interesaría el GIL; solo se plantea como un problema debido a la creciente prevalencia de sistemas multi-core.) Si quiere entenderlo en detalle, Puede ver este video o mirar este conjunto de diapositivas . Puede ser demasiada información, pero luego solicitó detalles :-)

Tenga en cuenta que el GIL de Python solo es realmente un problema para CPython, la implementación de referencia. Jython e IronPython no tienen un GIL. Como desarrollador de Python, generalmente no encuentras el GIL a menos que estés escribiendo una extensión C. Los autores de extensiones C deben liberar el GIL cuando sus extensiones bloquean las E / S, de modo que otros subprocesos en el proceso de Python tengan la oportunidad de ejecutarse.

Actualización: Enlace actualizado al video para apuntar a Youtube, ya que el enlace blip.tv anterior se había podrido.


Quiero compartir un ejemplo del libro multihebra para efectos visuales. Así que aquí está una clásica situación de bloqueo muerto

static void MyCallback(const Context &context){ Auto<Lock> lock(GetMyMutexFromContext(context)); ... EvalMyPythonString(str); //A function that takes the GIL ... }

Ahora considere los eventos en la secuencia resultando en un bloqueo muerto.

╔═══╦════════════════════════════════════════╦══════════════════════════════════════╗ ║ ║ Main Thread ║ Other Thread ║ ╠═══╬════════════════════════════════════════╬══════════════════════════════════════╣ ║ 1 ║ Python Command acquires GIL ║ Work started ║ ║ 2 ║ Computation requested ║ MyCallback runs and acquires MyMutex ║ ║ 3 ║ ║ MyCallback now waits for GIL ║ ║ 4 ║ MyCallback runs and waits for MyMutex ║ waiting for GIL ║ ╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝


Supongamos que tiene múltiples hilos que realmente no tocan los datos de los demás. Esos deberían ejecutarse tan independientemente como sea posible. Si tiene un "bloqueo global" que necesita adquirir para (por ejemplo) llamar a una función, eso puede terminar como un cuello de botella. En primer lugar, puede terminar sin obtener muchos beneficios de tener varios hilos.

Para ponerlo en una analogía del mundo real: imagina a 100 desarrolladores trabajando en una compañía con solo una taza de café. La mayoría de los desarrolladores pasaban el tiempo esperando el café en lugar de codificar.

Nada de esto es específico de Python. No sé los detalles de para qué Python necesitaba un GIL en primer lugar. Sin embargo, es de esperar que te haya dado una mejor idea del concepto general.




Por qué Python (CPython y otros) usa el GIL

Desde http://wiki.python.org/moin/GlobalInterpreterLock

En CPython, el bloqueo de intérprete global, o GIL, es un mutex que impide que varios subprocesos nativos ejecuten códigos de byte de Python a la vez. Este bloqueo es necesario principalmente porque la administración de memoria de CPython no es segura para subprocesos.

¿Cómo eliminarlo de Python?

Al igual que Lua, tal vez Python podría iniciar varias VM, pero Python no hace eso, creo que debería haber otras razones.

En Numpy o en alguna otra biblioteca extendida de Python, a veces, liberar el GIL a otros hilos podría aumentar la eficiencia de todo el programa.