2009-08-17 14 views
26

Así que noqueé algunos códigos de prueba para ver cómo el módulo de multiprocesamiento se escalaría en el trabajo vinculado a la CPU en comparación con el subprocesamiento. En Linux consigo el aumento de rendimiento que yo esperaría:python multiprocesamiento frente a subprocesos para trabajos encuadernados en cpu en Windows y Linux

linux (dual quad core xeon): 
serialrun took 1192.319 ms 
parallelrun took 346.727 ms 
threadedrun took 2108.172 ms 

Mi pro doble núcleo macbook muestra el mismo comportamiento:

osx (dual core macbook pro) 
serialrun took 2026.995 ms 
parallelrun took 1288.723 ms 
threadedrun took 5314.822 ms 

entonces fui y probado en una máquina de las ventanas y de algunos resultados muy diferentes.

windows (i7 920): 
serialrun took 1043.000 ms 
parallelrun took 3237.000 ms 
threadedrun took 2343.000 ms

¿Por qué, por qué, el enfoque de multiprocesamiento es mucho más lento en Windows?

Aquí está el código de prueba:

#!/usr/bin/env python 

import multiprocessing 
import threading 
import time 

def print_timing(func): 
    def wrapper(*arg): 
     t1 = time.time() 
     res = func(*arg) 
     t2 = time.time() 
     print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0) 
     return res 
    return wrapper 


def counter(): 
    for i in xrange(1000000): 
     pass 

@print_timing 
def serialrun(x): 
    for i in xrange(x): 
     counter() 

@print_timing 
def parallelrun(x): 
    proclist = [] 
    for i in xrange(x): 
     p = multiprocessing.Process(target=counter) 
     proclist.append(p) 
     p.start() 

    for i in proclist: 
     i.join() 

@print_timing 
def threadedrun(x): 
    threadlist = [] 
    for i in xrange(x): 
     t = threading.Thread(target=counter) 
     threadlist.append(t) 
     t.start() 

    for i in threadlist: 
     i.join() 

def main(): 
    serialrun(50) 
    parallelrun(50) 
    threadedrun(50) 

if __name__ == '__main__': 
    main()
+2

me encontré con su código de prueba en una de cuatro núcleos Dell PowerEdge 840 corriendo Win2K3, y los resultados no fueron tan dramáticos como el suyo, pero su punto sigue siendo válido: serialrun tomó 1266.000 ms parallelrun tomaron 1906.000 ms threadedrun tomó 4359.000 ms Estaré interesado en ver qué respuestas obtiene. Yo no me conozco – Jeff

Respuesta

15

Los procesos son mucho más ligeros en las variantes de UNIX. Los procesos de Windows son pesados ​​y toman mucho más tiempo para iniciarse. Los subprocesos son la forma recomendada de hacer multiproceso en Windows.

+0

Oh interesante, ¿significaría eso que un cambio en el resto de la prueba, digamos que contar más alto pero menos veces, permitiría a Windows recuperar algún rendimiento de multiprocesamiento? Lo intentaré. – manghole

+1

Probé la recalibración para contar hasta 10,000,000 y 8 iteraciones y los resultados están más a favor de Windows:

serialrun took 1651.000 ms parallelrun took 696.000 ms threadedrun took 3665.000 ms
manghole

4

Se ha dicho que la creación de procesos en Windows es más caro que en Linux. Si busca alrededor del sitio, encontrará información. Aquí está one Encontré fácilmente.

24

El python documentation for multiprocessing culpa a la falta de os.fork() de los problemas en Windows. Puede ser aplicable aquí.

Mira lo que sucede cuando importas psyco. En primer lugar, easy_install que:

C:\Users\hughdbrown>\Python26\scripts\easy_install.exe psyco 
Searching for psyco 
Best match: psyco 1.6 
Adding psyco 1.6 to easy-install.pth file 

Using c:\python26\lib\site-packages 
Processing dependencies for psyco 
Finished processing dependencies for psyco 

añadir esto a la parte superior de la secuencia de comandos de Python:

import psyco 
psyco.full() 

consigo estos resultados y sin:

serialrun took 1191.000 ms 
parallelrun took 3738.000 ms 
threadedrun took 2728.000 ms 

consigo estos resultados con:

serialrun took 43.000 ms 
parallelrun took 3650.000 ms 
threadedrun took 265.000 ms 

Paralelo todavía es lento, pero los otros queman caucho.

Editar: también, pruébelo con el grupo de multiprocesamiento. (Esta es mi primera vez probar esto y es tan rápido, que la figura Debo estar perdiendo algo).

@print_timing 
def parallelpoolrun(reps): 
    pool = multiprocessing.Pool(processes=4) 
    result = pool.apply_async(counter, (reps,)) 

Resultados:

C:\Users\hughdbrown\Documents\python\StackOverflow>python 1289813.py 
serialrun took 57.000 ms 
parallelrun took 3716.000 ms 
parallelpoolrun took 128.000 ms 
threadedrun took 58.000 ms 
+0

+1 para la buena optimización. –

+0

Muy limpio! Disminuyendo el número de iteraciones (procesos) mientras aumenta el valor de conteo muestra que, como dijo Byron, la lentitud paralela proviene del tiempo de configuración agregado de los Procesos de Windows. – manghole

+0

El Pool no parece esperar que se complete, hay un método join() para Pool pero no parece hacer lo que creo que debería hacer: P. – manghole

1

En la actualidad, la función de su contador() no está modificando tanto estado. Intente cambiar el contador() para que modifique muchas páginas de memoria. Luego ejecute un ciclo vinculado a la CPU. Vea si todavía hay una gran disparidad entre Linux y Windows.

No estoy ejecutando Python 2.6 en este momento, así que no puedo probarlo yo mismo.

1

El solo hecho de iniciar la agrupación lleva mucho tiempo. He encontrado en los programas del "mundo real" si puedo mantener un grupo abierto y reutilizarlo para muchos procesos diferentes, pasando la referencia hacia abajo a través de llamadas a métodos (generalmente usando el mapa.async) luego en Linux puedo ahorrar un pequeño porcentaje, pero en Windows a menudo puedo reducir a la mitad el tiempo empleado. Linux siempre es más rápido para mis problemas particulares, pero incluso en Windows obtengo beneficios netos del multiprocesamiento.

Cuestiones relacionadas