2009-08-17 10 views
26

Così ho messo a punto un codice di test per vedere come il modulo di multiprocessing si ridimensionasse sul lavoro con CPU rispetto al threading. Su Linux Ho l'aumento delle prestazioni che mi aspetto:python multiprocessing vs threading per lavoro con cpu legato su windows e linux

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

mio dual core MacBook Pro mostra lo stesso comportamento:

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

Allora sono andato e l'ho provato su una macchina Windows e avuto qualche risultati molto diversi.

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

Perché oh perché, l'approccio di multiprocessing è molto più lento su Windows?

Ecco il codice di prova:

#!/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

ho eseguito il codice di prova su un quad core Dell PowerEdge 840 in esecuzione Win2K3, ed i risultati non sono stati così drammatica come la tua, ma il vostro punto resta valida: serialrun preso 1266.000 ms parallelrun preso 1906.000 ms threadedrun preso 4.359,000 ms Sarò interessato a vedere quali risposte ottieni. Non mi conosco – Jeff

risposta

15

I processi sono molto più leggeri nelle varianti UNIX. I processi di Windows sono pesanti e richiedono molto più tempo per l'avvio. I thread sono il metodo consigliato per eseguire il multiprocessing su Windows.

+0

Oh interessante, allora ciò significherebbe che una modifica al bilanciamento del test, ad esempio il conteggio più alto ma meno volte, consentirebbe a Windows di recuperare alcune prestazioni multiprocessing? Farò un tentativo. – manghole

+1

Provato a ricalibrare a contare fino a 10.000.000 e 8 iterazioni ei risultati sono più a favore di Windows:

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

4

E 'stato detto che la creazione di processi su Windows è più costoso rispetto a Linux. Se cerchi nel sito troverai alcune informazioni. Ecco one l'ho trovato facilmente.

24

Il python documentation for multiprocessing accusa la mancanza di os.fork() per i problemi in Windows. Potrebbe essere applicabile qui.

Vedere cosa succede quando si importa psyco. In primo luogo, easy_install esso:

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 

Aggiungere questo alla parte superiore dello script python:

import psyco 
psyco.full() 

ottengo questi risultati senza:

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

ottengo questi risultati con:

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

Parallelo è ancora lento, ma gli altri bruciano gomma.

Modifica: anche, prova con il pool multiprocessing. (Questa è la mia prima volta cercando questo ed è così veloce, ho dato io devo essere perso qualcosa.)

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

Risultati:

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 per l'ottimizzazione piacevole. –

+0

Molto pulito! L'abbassamento del numero di iterazioni (processi) durante l'aumento del valore di conteggio indica che, come ha detto Byron, la lentezza parallela deriva dal tempo di installazione aggiunto dei processi di Windows. – manghole

+0

Il Pool non sembra aspettare da solo, c'è un metodo join() per Pool ma non sembra fare quello che penso dovrebbe fare: P. – manghole

1

Attualmente, il vostro contatore function() Non sta modificando molto stato. Prova a cambiare contatore() in modo che modifichi molte pagine di memoria. Quindi eseguire un ciclo associato alla CPU. Verifica se c'è ancora una grande disparità tra linux e windows.

Al momento non eseguo Python 2.6, quindi non posso provarlo da solo.

1

L'avvio della piscina richiede molto tempo. Ho trovato nei programmi del "mondo reale" se riesco a tenere aperto un pool e riutilizzarlo per molti processi diversi, passando il riferimento attraverso le chiamate al metodo (di solito usando la mappa.async) quindi su Linux posso risparmiare qualche percento ma su Windows posso dimezzare il tempo impiegato. Linux è sempre più veloce per i miei problemi particolari, ma anche su Windows ottengo benefici netti dal multiprocessing.

Problemi correlati