¿Cuál es exactamente la función del bloqueo de intérprete global de Python? ¿Otros lenguajes que se compilan para bytecode emplean un mecanismo similar?
¿Cuál es exactamente la función del bloqueo de intérprete global de Python? ¿Otros lenguajes que se compilan para bytecode emplean un mecanismo similar?
Respuestas:
En general, para cualquier problema de seguridad de subprocesos, deberá proteger sus estructuras de datos internas con bloqueos. Esto se puede hacer con varios niveles de granularidad.
Puede usar un bloqueo de grano fino, donde cada estructura separada tiene su propio bloqueo.
Puede utilizar un bloqueo de grano grueso donde un bloqueo protege todo (el enfoque GIL).
Hay varios pros y contras de cada método. El bloqueo detallado permite un mayor paralelismo: dos subprocesos se pueden ejecutar en paralelo cuando no comparten ningún recurso. Sin embargo, hay una sobrecarga administrativa mucho mayor. Para cada línea de código, es posible que deba adquirir y liberar varios bloqueos.
El enfoque de grano grueso es el opuesto. No se pueden ejecutar dos subprocesos al mismo tiempo, pero un subproceso individual se ejecutará más rápido porque no hace tanta contabilidad. En última instancia, todo se reduce a un compromiso entre la velocidad de un solo subproceso y el paralelismo.
Ha habido algunos intentos de eliminar el GIL en Python, pero la sobrecarga adicional para las máquinas de un solo subproceso era generalmente demasiado grande. Algunos casos pueden ser más lentos incluso en máquinas multiprocesador debido a la contención de bloqueo.
¿Otros lenguajes que se compilan para código de bytes emplean un mecanismo similar?
Varía y probablemente no debería considerarse una propiedad del lenguaje tanto como una propiedad de implementación. Por ejemplo, existen implementaciones de Python como Jython e IronPython que utilizan el enfoque de subprocesamiento de su VM subyacente, en lugar de un enfoque GIL. Además, la próxima versión de Ruby parece estar en movimiento. hacia la introducción de un GIL.
Lo siguiente es del Manual de referencia oficial de la API de Python / C :
El intérprete de Python no es completamente seguro para subprocesos. Para admitir programas de Python de subprocesos múltiples, existe un bloqueo global que debe mantener el subproceso actual antes de que pueda acceder de forma segura a los objetos de Python. Sin el bloqueo, incluso las operaciones más simples podrían causar problemas en un programa de subprocesos múltiples: por ejemplo, cuando dos subprocesos incrementan simultáneamente el recuento de referencias del mismo objeto, el recuento de referencias podría terminar incrementándose solo una vez en lugar de dos.
Por lo tanto, existe la regla de que solo el subproceso que ha adquirido el bloqueo de intérprete global puede operar en objetos de Python o llamar a funciones de API de Python / C. Para admitir programas de Python de múltiples subprocesos, el intérprete libera y vuelve a adquirir el bloqueo con regularidad; de forma predeterminada, cada 100 instrucciones de código de bytes (esto se puede cambiar con sys.setcheckinterval ()). El bloqueo también se libera y se vuelve a adquirir alrededor del bloqueo potencial de las operaciones de E / S como leer o escribir un archivo, de modo que otros subprocesos puedan ejecutarse mientras el subproceso que solicita la E / S espera a que se complete la operación de E / S.
Creo que resume bastante bien la cuestión.
El bloqueo de intérprete global es un gran bloqueo de tipo mutex que evita que los contadores de referencia se manguen. Si está escribiendo código Python puro, todo esto sucede detrás de escena, pero si incrusta Python en C, es posible que tenga que tomar / liberar explícitamente el bloqueo.
Este mecanismo no está relacionado con la compilación de Python en código de bytes. No es necesario para Java. De hecho, ni siquiera es necesario para Jython (python compilado en jvm).
ver también esta pregunta
Python, como perl 5, no fue diseñado desde cero para ser seguro para subprocesos. Los subprocesos se injertaron después del hecho, por lo que el bloqueo del intérprete global se usa para mantener la exclusión mutua cuando solo un subproceso está ejecutando código en un momento dado en las entrañas del intérprete.
Los subprocesos de Python individuales son multitarea cooperativamente por el propio intérprete al ciclar el bloqueo de vez en cuando.
Es necesario agarrar el candado usted mismo cuando está hablando con Python desde C cuando otros subprocesos de Python están activos para 'participar' en este protocolo y asegurarse de que no ocurra nada inseguro a sus espaldas.
Otros sistemas que tienen una herencia de un solo subproceso que luego evolucionaron a sistemas de múltiples subprocesos a menudo tienen algún mecanismo de este tipo. Por ejemplo, el kernel de Linux tiene el "Big Kernel Lock" de sus primeros días de SMP. Gradualmente, con el tiempo, a medida que el rendimiento de subprocesos múltiples se convierte en un problema, existe una tendencia a tratar de romper este tipo de bloqueos en piezas más pequeñas o reemplazarlos con algoritmos sin bloqueos y estructuras de datos donde sea posible para maximizar el rendimiento.
reiserfs
, la única razón real por la que lo sé).
Con respecto a su segunda pregunta, no todos los lenguajes de scripting usan esto, pero solo los hace menos poderosos. Por ejemplo, los hilos en Ruby son verdes. y no nativos.
En Python, los subprocesos son nativos y GIL solo evita que se ejecuten en diferentes núcleos.
En Perl, los hilos son aún peores. Simplemente copian todo el intérprete y están lejos de ser tan utilizables como en Python.
Quizás este artículo del BDFL ayude.