2009-08-04 22 views
32

Tengo una aplicación de Python que toma una colección de datos y para cada pieza de datos en esa colección realiza una tarea. La tarea tarda un tiempo en completarse ya que hay un retraso involucrado. Debido a este retraso, no quiero que cada dato realice la tarea posteriormente, quiero que todos sucedan en paralelo. ¿Debo usar multiprocesos? o enhebrar para esta operación?multiproceso o subprocesamiento en python?

Intenté utilizar el enhebrado pero tuve algunos problemas, a menudo algunas de las tareas nunca se activaron.

+0

¿Qué tan grande es su "colección de datos". Si es enorme, es posible que no desee iniciar subprocesos o procesos para cada uno. –

+0

generalmente 1, 2 o 3 datos. – Ryan

+0

@ S.Lott: ¿cómo limitaría el número de subprocesos/procesos a un número mucho más pequeño que el tamaño de los datos? –

Respuesta

0

Usando modelo de hilos de CPython no le dará ninguna mejora en el rendimiento, ya que los hilos no son en realidad ejecutar en paralelo, debido a la forma en que se maneja la recolección de basura. El multiproceso permitiría la ejecución paralela. Obviamente, en este caso, debe tener múltiples núcleos disponibles para cultivar sus trabajos paralelos.

Hay mucha más información disponible en this related question.

+4

Esto no es verdad. No le proporcionará MUCHA mejora en el rendimiento como lo hará en, por ejemplo, C o C++, pero se produce cierta concurrencia. Especialmente si está obligado a E/S, los hilos ayudan. – Christopher

+0

No me había dado cuenta de eso, gracias por la información. Aquí hay una referencia externa: http://mail.python.org/pipermail/python-dev/2008-May/079461.html. En este punto de referencia, puede ver la mejora de los problemas vinculados a E/S que describe. Sin embargo, vale la pena señalar que el problema de CPU se ejecutó ** más lentamente ** con 2 subprocesos de Python que con 1. Parece que perfilar tu aplicación es esencial. –

7

Para las pequeñas colecciones de datos, basta con crear subprocesos con subprocess.Popen.

Cada subproceso puede conseguir simplemente es parte de los datos de la entrada estándar o desde argumentos de línea de comandos, haga su procesamiento, y simplemente grabar el resultado en un archivo de salida.

Cuando los subprocesos tienen todo terminado (o el tiempo de espera), sólo tiene que fusionar los archivos de salida.

Muy simple.

+3

Esta es una solución realmente pesada. No solo tiene que hacer arreglos para alimentar los datos a un proceso externo, tiene una sobrecarga masiva. – Christopher

+1

@Christopher. El punto es simplicidad. El mundo de Unix ha estado usando esta técnica durante 40 años. Funciona bien porque es simple. Además, la sobrecarga no es realmente "masiva" ya que está ejecutando varias instancias de la misma imagen binaria. Esto está bien optimizado por GNU/Linux. –

+8

@ S.Lott: El hecho de que se haya utilizado durante mucho tiempo no significa que sea una buena solución. En particular, no es una buena solución para problemas de cálculo. La sobrecarga es "masiva" porque tiene la sobrecarga de memoria de todas las estructuras por proceso, así como la latencia de las múltiples transiciones del kernel. El módulo de multiprocesamiento de python realmente no crea un nuevo "proceso" como lo hace el subproceso. Crea un nuevo contexto de intérprete, que es mucho más ligero que crear un nuevo proceso de nivel de sistema operativo. – Christopher

7

Puede considerar buscar en Stackless Python. Si tiene control sobre la función que lleva mucho tiempo, puede simplemente arrojar algunos stackless.schedule() s allí (diciendo ceder a la siguiente coroutine), o bien puede set Stackless to preemptive multitasking.

En Stackless, que no tienen las discusiones, pero tasklets o Verdecillo que son esencialmente hilos muy ligero. Funciona de maravilla en el sentido de que hay un marco bastante bueno con muy poca configuración para realizar múltiples tareas.

Sin embargo, Stackless dificulta la portabilidad ya que hay que sustituir algunas de las bibliotecas estándar de Python - Stackless elimina la dependencia de la pila C. Es muy portátil si el siguiente usuario también tiene Stackless instalado, pero rara vez será el caso.

29

Si realmente está computar obligado, mediante el multiprocessing module es probablemente la solución más ligera de peso (en términos de consumo de memoria y dificultades de implementación.)

Si usted es de E/S de la envolvente, utilizando los threading module normalmente dará buenos resultados Asegúrese de utilizar el almacenamiento seguro de subprocesos (como la cola) para entregar datos a sus subprocesos. O bien, proporciónales una única pieza de datos que sea única para ellos cuando se generen.

PyPy se centra en el rendimiento. Tiene una serie de características que pueden ayudar con el procesamiento de procesamiento computarizado. También tienen soporte para Software Transactional Memory, aunque todavía no es calidad de producción. La promesa es que puede usar mecanismos paralelos o concurrentes más simples que el multiprocesamiento (que tiene algunos requisitos incómodos).

Stackless Python es también una buena idea. Stackless tiene problemas de portabilidad como se indicó anteriormente. Unladen Swallow fue prometedor, pero ahora ha desaparecido.Pyston es otra implementación (inacabada) de Python centrada en la velocidad. Adopta un enfoque diferente de PyPy, que puede producir mejores (o solo diferentes) aceleraciones.

0

Si puede dividir y separar fácilmente los datos que tiene, parece que debe hacer esa partición externamente y alimentarlos a varios procesos de su programa. (es decir, varios procesos en lugar de hilos)

0

IronPython tiene multihilo real, a diferencia de CPython y es GIL. Entonces, dependiendo de lo que estés haciendo, puede valer la pena mirarlo. Pero parece que su caso de uso se adapta mejor al módulo de multiprocesamiento.

Para el tipo que recomienda python sin apilamiento, no soy un experto en eso, pero me parece que está hablando de software "multihilo", que en realidad no es para nada paralelo (todavía se ejecuta en un hilo físico, por lo tanto, no se puede escalar a varios núcleos). Es simplemente una forma alternativa de estructurar aplicaciones asíncronas (pero aún de un solo subproceso, no paralelas).

9

Tareas se ejecuta de forma secuencial pero tiene la ilusión de que se ejecutan en paralelo. Las tareas son buenas cuando se utiliza para E/S de archivos o conexiones y porque son ligeras.

El multiproceso con Pool puede ser la solución adecuada para usted porque los procesos se ejecutan en paralelo, por lo que son muy buenos con la informática intensiva porque cada proceso se ejecuta en una CPU (o núcleo).

instalación de multiproceso puede ser muy fácil:

from multiprocessing import Pool 

def worker(input_item): 
    output = do_some_work() 
    return output 

pool = Pool() # it make one process for each CPU (or core) of your PC. Use "Pool(4)" to force to use 4 processes, for example. 
list_of_results = pool.map(worker, input_list) # Launch all automatically 
+0

¿significa que todos los núcleos trabajan con los mismos datos? ¿es posible dividir input_list y pasar cada fragmento a diferentes núcleos? – Moj

0

Es posible que desee ver en Twisted. Está diseñado para tareas de red asíncronas.

Cuestiones relacionadas