Hilos de Python todos ejecutándose en un solo núcleo

Tengo un progtwig Python que genera muchos hilos, ejecuta 4 a la vez, y cada uno realiza una operación costosa. Pseudocódigo

for object in list: t = Thread(target=process, args=(object)) # if fewer than 4 threads are currently running, t.start(). Otherwise, add t to queue 

Pero cuando se ejecuta el progtwig, el Monitor de actividad en OS X muestra que 1 de los 4 núcleos lógicos está al 100% y los demás casi a 0. Obviamente, no puedo forzar al sistema operativo a hacer nada, pero nunca tuve que hacerlo. Preste atención al rendimiento en el código de subprocesos múltiples como este antes, así que me preguntaba si solo faltaba o no entendía algo.

Gracias.

Tenga en cuenta que en muchos casos (y en prácticamente todos los casos en los que su “operación costosa” es un cálculo implementado en Python), varios subprocesos no se ejecutarán simultáneamente debido al Bloqueo global de intérprete de Python (GIL) .

El GIL es un locking de nivel de intérprete. Este locking impide la ejecución de varios subprocesos a la vez en el intérprete de Python. Cada subproceso que desea ejecutar debe esperar a que GIL sea liberado por el otro subproceso, lo que significa que su aplicación Python de subprocesos múltiples es esencialmente un solo subproceso, ¿verdad? Sí. No exactamente. Una especie de

CPython utiliza lo que se denomina subprocesos de “sistema operativo” debajo de las cubiertas, es decir, cada vez que se realiza una solicitud para crear un nuevo subproceso, el intérprete realmente llama a las bibliotecas y al núcleo del sistema operativo para generar un nuevo subproceso. Esto es lo mismo que Java, por ejemplo. Por lo tanto, en la memoria realmente tiene varios subprocesos y normalmente el sistema operativo controla qué subprocesos está progtwigdo para ejecutarse. En una máquina con múltiples procesadores, esto significa que puede tener muchos hilos distribuidos en varios procesadores, todos felizmente trabajando en el trabajo.

Sin embargo, aunque CPython utiliza subprocesos del sistema operativo (en teoría, permite que se ejecuten varios subprocesos dentro del intérprete simultáneamente), el intérprete también obliga a GIL a adquirir un subproceso antes de que pueda acceder al intérprete y la stack, y puede modificar los objetos de Python en la memoria. todo a la fuerza El último punto es por qué existe la GIL: la GIL impide el acceso simultáneo a los objetos de Python por varios subprocesos. Pero esto no te salva (como lo ilustra el ejemplo del Banco) de ser una criatura sensible a la cerradura; no consigues un viaje gratis El GIL está allí para proteger la memoria de los intérpretes, no su cordura.

Consulte la sección Bloqueo global de intérpretes de la publicación de Jesse Noller para obtener más detalles.

Para solucionar este problema, consulte el módulo de multiprocesamiento de Python .

Los procesos múltiples (con un uso juicioso de IPC) son un […] enfoque mucho mejor para escribir aplicaciones para cuadros de múltiples CPU que los subprocesos.

– Guido van Rossum (creador de Python)

Python tiene un locking de intérprete global, que puede evitar que los subprocesos de código interpretado se procesen simultáneamente.

http://en.wikipedia.org/wiki/Global_Interpreter_Lock

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

Para conocer las formas de solucionar esto, pruebe el módulo de multiprocesamiento , como se recomienda aquí:

¿La ejecución de procesos de Python separados evita la GIL?

AFAIK, en CPython, el locking global de intérpretes significa que no puede haber más de un bloque de código Python ejecutándose a la vez. Aunque esto no afecta realmente a nada en un solo procesador / máquina de un solo núcleo, en una máquina de múltiples puntos significa que efectivamente solo hay un subproceso ejecutándose a la vez, lo que hace que todo el otro núcleo esté inactivo.