2009-08-17 5 views
26

J'ai donc mis un peu de code de test pour voir comment le module multiprocesseur évoluerait sur le travail lié cpu par rapport au threading. Sur linux je reçois l'augmentation de la performance que je pense:multiprocessing python vs threading pour le travail lié cpu sur windows et linux

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

Mon pro dual core macbook montre le même comportement:

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

Je suis ensuite allé et essayé sur une machine Windows et a obtenu quelques-uns résultats très différents. Pourquoi, pourquoi l'approche multitraitement est-elle tellement plus lente sur Windows?

Voici le code de test:

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

J'ai couru votre code de test sur un quad core Dell PowerEdge 840 en cours d'exécution Win2K3, et les résultats ne sont pas aussi dramatiques que le vôtre, mais votre point reste valable: serialrun a pris 1266.000 ms parallelrun ont 1906.000 ms threadedrun a pris 4359,000 ms Je serais intéressé de voir quelles réponses vous obtiendrez. Je ne me connais pas. – Jeff

Répondre

15

Les processus sont beaucoup plus légers sous les variantes UNIX. Les processus Windows sont lourds et prennent beaucoup plus de temps pour démarrer. Les threads sont la manière recommandée de faire du multitraitement sur Windows.

+0

Oh intéressant, alors cela signifierait-il qu'une modification du solde du test, disons compter plus haut mais moins de temps, permettrait à Windows de récupérer des performances de multitraitement? Je vais essayer. – manghole

+1

Essayé de recalibrer à compter à 10.000.000 et 8 itérations et les résultats sont plus en faveur de Windows:

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

4

On a dit que la création de processus sous Windows est plus cher que sur linux. Si vous recherchez autour du site, vous trouverez quelques informations. Voici one j'ai trouvé facilement.

24

Le python documentation for multiprocessing accuse le manque de os.fork() pour les problèmes dans Windows. Cela peut être applicable ici.

Voir ce qui se passe lorsque vous importez psyco. Tout d'abord, easy_install il:

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 

Ajouter ce en haut de votre script python:

import psyco 
psyco.full() 

Je reçois ces résultats sans:

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

Je reçois ces résultats avec:

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

Parallèle est encore lent, mais les autres brûlent du caoutchouc. Editer: aussi, essayez-le avec le pool de multitraitement. (Ceci est ma première fois d'essayer cela et il est si rapide, je me dis que je dois manquer quelque chose.)

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

Résultats:

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 pour la belle optimisation. –

+0

Très soigné! Réduire le nombre d'itérations (processus) tout en augmentant la valeur count-to montre que, comme l'a dit Byron, la lenteur du parallélisme vient du temps d'installation ajouté des processus Windows. – manghole

+0

Le pool ne semble pas attendre pour se terminer, il existe une méthode join() pour Pool mais il ne semble pas faire ce que je pense qu'il devrait faire: P. – manghole

1

Actuellement, votre fonction compteur() ne modifie beaucoup Etat. Essayez de changer counter() pour qu'il modifie de nombreuses pages de mémoire. Ensuite, exécutez une boucle liée au processeur. Voyez s'il existe encore une grande disparité entre Linux et Windows.

Je n'utilise pas python 2.6 maintenant, donc je ne peux pas l'essayer moi-même.

1

Le démarrage de la piscine prend beaucoup de temps. J'ai trouvé dans les programmes 'real world' si je peux garder un pool ouvert et le réutiliser pour de nombreux processus différents, en passant la référence par des appels de méthodes (en utilisant généralement map.async) puis sur Linux je peux économiser quelques pour cent mais sur Windows je peux souvent réduire de moitié le temps pris. Linux est toujours plus rapide pour mes problèmes particuliers, mais même sous Windows, j'obtiens des avantages nets du multitraitement.

Questions connexes