¿Python admite subprocesos múltiples? ¿Puede acelerar el tiempo de ejecución?

95

Estoy un poco confundido acerca de si el multiproceso funciona en Python o no.

Sé que ha habido muchas preguntas sobre esto y he leído muchas de ellas, pero todavía estoy confundido. Sé por mi propia experiencia y he visto a otros publicar sus propias respuestas y ejemplos aquí en StackOverflow que el multiproceso es posible en Python. Entonces, ¿por qué todo el mundo sigue diciendo que Python está bloqueado por GIL y que solo se puede ejecutar un hilo a la vez? Claramente funciona. ¿O hay alguna distinción que no estoy obteniendo aquí?

Muchos carteles / encuestados también siguen mencionando que el enhebrado es limitado porque no utiliza múltiples núcleos. Pero diría que siguen siendo útiles porque funcionan simultáneamente y, por lo tanto, hacen que la carga de trabajo combinada se realice más rápido. Quiero decir, ¿por qué habría un módulo de hilo de Python de otra manera?

Actualizar:

Gracias por todas las respuestas hasta el momento. La forma en que lo entiendo es que el subproceso múltiple solo se ejecutará en paralelo para algunas tareas de E / S, pero solo se puede ejecutar una a la vez para las tareas de múltiples núcleos vinculados a la CPU.

No estoy del todo seguro de lo que esto significa para mí en términos prácticos, así que solo daré un ejemplo del tipo de tarea que me gustaría realizar en múltiples hilos. Por ejemplo, digamos que quiero recorrer una lista muy larga de cadenas y quiero hacer algunas operaciones básicas de cadena en cada elemento de la lista. Si divido la lista, envío cada sublista para que sea procesada por mi código de ciclo / cadena en un nuevo hilo y devuelvo los resultados en una cola, ¿se ejecutarán estas cargas de trabajo aproximadamente al mismo tiempo? Lo más importante, ¿teóricamente acelerará esto el tiempo que lleva ejecutar el script?

Otro ejemplo podría ser si puedo renderizar y guardar cuatro imágenes diferentes usando PIL en cuatro subprocesos diferentes, y ¿esto será más rápido que procesar las imágenes una por una después de la otra? Supongo que este componente de velocidad es lo que realmente me pregunta en lugar de cuál es la terminología correcta.

También conozco el módulo de multiprocesamiento, pero mi principal interés en este momento es para cargas de tareas pequeñas a medianas (10-30 segundos), por lo que creo que el subproceso múltiple será más apropiado porque los subprocesos pueden ser lentos para iniciar.

Karim Bahgat
fuente
4
Esta es una pregunta bastante cargada. Creo que la respuesta está en lo que quieres que hagan los hilos. En la mayoría de las circunstancias, GIL evita que se ejecute más de un hilo simultáneamente. Sin embargo, hay algunos casos en los que se libera el GIL (por ejemplo, leyendo de un archivo) para que se pueda hacer en paralelo. También tenga en cuenta que el GIL es un detalle de implementación de Cpython (la implementación más común). Ninguna otra implementación de python (Jython, PyPy, etc.) tiene un GIL (AFAIK)
mgilson
2
@mgilson PyPy tiene un GIL.
2
@delnan - Pareces tener razón. Gracias.
mgilson
1
"Los subprocesos pueden tardar en iniciarse"; podría crear un grupo de tareas listas para ejecutarse. La sobrecarga puede limitarse aproximadamente a la cantidad de tiempo que se tarda en serializar / deserializar los datos necesarios para que la tarea comience a funcionar.
Brian Cain
1
@KarimBahgat, eso es exactamente lo que quiero decir.
Brian Cain

Respuestas:

132

El GIL no evita el enhebrado. Todo lo que hace GIL es asegurarse de que solo un hilo esté ejecutando código Python a la vez; el control todavía cambia entre hilos.

Entonces, lo que GIL evita es hacer uso de más de un núcleo de CPU o CPU independientes para ejecutar subprocesos en paralelo.

Esto solo se aplica al código Python. Las extensiones de C pueden liberar GIL para permitir que varios subprocesos de código C y un subproceso de Python se ejecuten en varios núcleos. Esto se extiende a las E / S controladas por el kernel, como las select()llamadas para lecturas y escrituras de sockets, lo que hace que Python maneje los eventos de red de manera razonablemente eficiente en una configuración multiproceso de múltiples núcleos.

Lo que hacen muchas implementaciones de servidor es ejecutar más de un proceso de Python, para permitir que el sistema operativo maneje la programación entre procesos para utilizar los núcleos de su CPU al máximo. También puede usar la multiprocessingbiblioteca para manejar el procesamiento paralelo en múltiples procesos desde una base de código y un proceso principal, si eso se adapta a sus casos de uso.

Tenga en cuenta que el GIL solo es aplicable a la implementación de CPython; Jython y IronPython utilizan una implementación de subprocesos diferente (los subprocesos de tiempo de ejecución comunes de Java VM y .NET, respectivamente).

Para abordar su actualización directamente: cualquier tarea que intente obtener un aumento de velocidad de la ejecución paralela, utilizando código Python puro, no verá una aceleración ya que el código Python enhebrado está bloqueado en un hilo que se ejecuta a la vez. Sin embargo, si mezcla extensiones C y E / S (como PIL u operaciones numpy) y cualquier código C puede ejecutarse en paralelo con un hilo Python activo.

El subproceso de Python es excelente para crear una GUI receptiva o para manejar múltiples solicitudes web cortas donde la E / S es el cuello de botella más que el código Python. No es adecuado para paralelizar código Python computacionalmente intensivo, adherirse al multiprocessingmódulo para tales tareas o delegar en una biblioteca externa dedicada.

Martijn Pieters
fuente
Gracias @MartijnPieters, entonces tengo una respuesta más clara a mi pregunta sobre si el subproceso se puede utilizar para acelerar el código como un bucle for, que es "no". Tal vez usted o alguien podría escribir una nueva respuesta que pueda aceptar que proporcione algunos ejemplos específicos de módulos / códigos / operaciones comunes donde GIL permitirá que el subprocesamiento se ejecute en paralelo y, por lo tanto, más rápido (por ejemplo, ejemplos de esas E / S y redes / operaciones de lectura de socket que se han mencionado, y cualquier otro caso en el que sea útil el multiproceso en Python). ¿Quizás una buena lista de usos comunes de subprocesos múltiples y algunos ejemplos de programación si es posible?
Karim Bahgat
4
No, no creo que esa respuesta sea de mucha ayuda; sinceramente. Nunca puede crear una lista exhaustiva, pero la regla general es que cualquier E / S (lectura y escritura de archivos, sockets de red, tuberías) se maneja en C, y muchas bibliotecas de C también liberan el GIL para sus operaciones, pero depende de las bibliotecas documentar esto por usted.
Martijn Pieters
1
Mi mal, no vi su respuesta actualizada hasta ahora, donde dio algunos buenos ejemplos de uso de hilos. Estos incluían (corregirme si me equivoco) programación de red (por urllib.urlopen()ejemplo Image.transform(),? ), Para llamar a un script de Python desde dentro de una GUI de Python y llamar a múltiples numpy.array()operaciones PIL (por ejemplo ) y numpy (por ejemplo ) con subprocesos. Y proporcionó algunos ejemplos más en su comentario, como el uso de varios hilos para leer archivos (por ejemplo f.read(),?). Sé que no es posible una lista exhaustiva, solo quería los tipos de ejemplos que dio en su actualización. De cualquier manera, acepté su respuesta :)
Karim Bahgat
2
@KarimBahgat: Sí, urllib.urlopen()invocaría sockets de red, esperar la E / S de socket es una excelente oportunidad para cambiar de hilo y hacer otra cosa.
Martijn Pieters
4
Aunque no es directamente relevante para este problema, vale la pena señalar que a veces el subproceso no tiene nada que ver con el rendimiento; Puede que sea más sencillo escribir su código como múltiples hilos de ejecución independientes. Por ejemplo, es posible que un hilo reproduzca música de fondo, otro que preste servicio a la interfaz de usuario y otro que se dedique a realizar cálculos que se deben realizar con el tiempo, pero que no tienen prisa. Intentar secuenciar la reproducción del siguiente búfer de audio con el bucle de ejecución de la interfaz de usuario, o dividir su cálculo en partes lo suficientemente pequeñas como para no interferir con la interactividad, puede ser mucho más difícil que usar hilos.
abarnert
4

Si. :)

Tiene el módulo de roscado de bajo nivel y el módulo de roscado de nivel superior . Pero si simplemente desea utilizar máquinas multinúcleo, el módulo de multiprocesamiento es el camino a seguir.

Cita de los documentos :

En CPython, debido al bloqueo de intérprete global, solo un subproceso puede ejecutar código Python a la vez (aunque ciertas bibliotecas orientadas al rendimiento pueden superar esta limitación). Si desea que su aplicación haga un mejor uso de los recursos computacionales de las máquinas de varios núcleos, se recomienda utilizar el multiprocesamiento. Sin embargo, el subprocesamiento sigue siendo un modelo apropiado si desea ejecutar varias tareas vinculadas a E / S simultáneamente.

zord
fuente
3

El subproceso está permitido en Python, el único problema es que GIL se asegurará de que solo se ejecute un subproceso a la vez (sin paralelismo).

Entonces, básicamente, si desea realizar múltiples subprocesos en el código para acelerar el cálculo, no lo acelerará ya que solo se ejecuta un subproceso a la vez, pero si lo usa para interactuar con una base de datos, por ejemplo, lo hará.

r.guerbab
fuente