2012-07-11 6 views
36

Lassen Sie uns den Einsatz zum Beispiel numpy.sin()Parallelisierung eine Numpy Vektoroperation

Der folgende Code den Wert des Sinus für jeden Wert des Arrays a zurück:

import numpy 
a = numpy.arange(1000000) 
result = numpy.sin(a) 

Aber meine Maschine verfügt über 32 Kerne Also möchte ich sie benutzen. (Der Overhead könnte sich für etwas wie numpy.sin() nicht lohnen, aber die Funktion, die ich eigentlich verwenden möchte, ist ein wenig komplizierter und ich werde mit einer großen Datenmenge arbeiten.)

Ist das das Beste (lies: intelligenteste oder schnellste) Methode:

from multiprocessing import Pool 
if __name__ == '__main__': 
    pool = Pool() 
    result = pool.map(numpy.sin, a) 

oder gibt es eine bessere Möglichkeit, dies zu tun?

+0

Wenn Sie 'pool.map()' verwenden, sollten Sie 'math.sin' verwenden, da es schneller ist als' numpy.sin'. Referenz: http://stackoverflow.com/questions/3650194/are-numpys-math-functions-faster-than-pythons. – EOL

+2

Für 'numpy.sin' sagt das [offizielle numpy/scipy Wiki] (http://wiki.scipy.org/ParallelProgramming), dass es parallel funktionieren sollte, wenn Sie [compiliere numpy mit openmp aktiviert haben] (https: // software.intel.com/de-de/articles/numpyscipy-with-intel-mkl). – ziyuang

+0

Sie könnten auch [Bohrium] (http://bohrium.readthedocs.io/) verwenden: Es sollte so einfach sein, wie Ihre erste Zeile mit 'import bohrium als numpy' zu ersetzen ... – j08lue

Antwort

48

Es ist ein besserer Weg: numexpr

Etwas von ihrer Hauptseite umformuliert:

Es ist ein Multi-Threaded-VM in C geschrieben, die Ausdrücke analysiert, umschreibt sie effizienter und stellt sie zusammen auf Der Fly-in-Code, der nahezu optimale parallele Leistung für Speicher- und CPU-beschränkte Operationen erreicht.

Zum Beispiel, in meiner 4-Kern-Maschine ist die Auswertung eines Sinus nur etwas weniger als 4 mal schneller als numpy.

In [1]: import numpy as np 
In [2]: import numexpr as ne 
In [3]: a = np.arange(1000000) 
In [4]: timeit ne.evaluate('sin(a)') 
100 loops, best of 3: 15.6 ms per loop  
In [5]: timeit np.sin(a) 
10 loops, best of 3: 54 ms per loop 

Dokumentation, einschließlich der unterstützten Funktionen here. Sie müssen überprüfen oder uns mehr Informationen geben, um zu sehen, ob Ihre kompliziertere Funktion von numexpr ausgewertet werden kann.

+4

Ich schrieb meinen Code mit numexpr und es führt etwa 6 mal schneller als der gleiche Code mit numpig. Vielen Dank für den Vorschlag! Jetzt frage ich mich, warum NUMEXPR nicht mehr verbreitet ist. Bei all meinen Suchen nach numerischen Paketen in Python bin ich bisher nicht darauf gestoßen. Es gab auch eine kleine Belästigung in numexpr, die keine Array-Indexierung unterstützt, aber das war kaum ein Rückschlag. – user1475412

+1

Vielleicht sollten Sie auch Theano und Cython dann überprüfen. Theano kann GPUs verwenden, aber ich habe es nicht wirklich benutzt, daher kann ich Ihnen kein Beispiel geben. – jorgeca

+2

Ein Grund, warum NUMEXPR nicht weiter verbreitet ist, ist die Tatsache, dass es umständlicher ist als reines NumPy (wie im obigen Beispiel). Es ist in der Tat großartig, um NumPy-Berechnungen zu beschleunigen, als schneller laufen zu müssen. – EOL

17

Nun diese Art von interessantem Detail ist, wenn Sie die folgenden Befehle ausführen:

import numpy 
from multiprocessing import Pool 
a = numpy.arange(1000000)  
pool = Pool(processes = 5) 
result = pool.map(numpy.sin, a) 

UnpicklingError: NEWOBJ class argument has NULL tp_new 

erwarten nicht, dass so was geht, gut:

>>> help(numpy.sin) 
    Help on ufunc object: 

sin = class ufunc(__builtin__.object) 
| Functions that operate element by element on whole arrays. 
| 
| To see the documentation for a specific ufunc, use np.info(). For 
| example, np.info(np.sin). Because ufuncs are written in C 
| (for speed) and linked into Python with NumPy's ufunc facility, 
| Python's help() function finds this page whenever help() is called 
| on a ufunc. 

yep numpy.sin wird in c als solche implementiert man nicht wirklich direkt mit Multiprocessing verwenden können.

so müssen wir es mit einer anderen Funktion wickeln

perf:

import time 
import numpy 
from multiprocessing import Pool 

def numpy_sin(value): 
    return numpy.sin(value) 

a = numpy.arange(1000000) 
pool = Pool(processes = 5) 

start = time.time() 
result = numpy.sin(a) 
end = time.time() 
print 'Singled threaded %f' % (end - start) 
start = time.time() 
result = pool.map(numpy_sin, a) 
pool.close() 
pool.join() 
end = time.time() 
print 'Multithreaded %f' % (end - start) 


$ python perf.py 
Singled threaded 0.032201 
Multithreaded 10.550432 

wow, hatte nicht erwartet, dass entweder, auch ein paar Fragen für den Anfang Theres wir eine Python-Funktion auch verwenden Wenn es nur ein Wrapper gegen eine reine c-Funktion ist und auch der Aufwand für das Kopieren der Werte ist, teilt Multiprocessing standardmäßig keine Daten, so dass jeder Wert kopiert werden muss.

Sie beachten Sie, dass bei ordnungsgemäßem Segment unserer Daten:

import time 
import numpy 
from multiprocessing import Pool 

def numpy_sin(value): 
    return numpy.sin(value) 

a = [numpy.arange(100000) for _ in xrange(10)] 
pool = Pool(processes = 5) 

start = time.time() 
result = numpy.sin(a) 
end = time.time() 
print 'Singled threaded %f' % (end - start) 
start = time.time() 
result = pool.map(numpy_sin, a) 
pool.close() 
pool.join() 
end = time.time() 
print 'Multithreaded %f' % (end - start) 

$ python perf.py 
Singled threaded 0.150192 
Multithreaded 0.055083 

Also, was können wir daraus nehmen, Multiprozessing groß ist, aber wir sollten immer testen und vergleichen sie ihre manchmal schneller und manchmal seine langsamer, je nachdem, wie sein verwendet ...

Zugegeben, Sie verwenden nicht numpy.sin, aber eine andere Funktion würde ich Ihnen empfehlen zuerst zu überprüfen, dass in der Tat Multiprocessing die Berechnung beschleunigen wird, möglicherweise der Overhead des Kopierens von Werten zurück/her Sie beeinflussen kann.

So oder so ich auch glaube, dass pool.map ist die beste, sicherste Methode des Multithreading-Code ...

Ich hoffe, das hilft.

+0

Vielen Dank! Dies ist sehr informativ. Ich hatte angenommen, basierend auf dem, was ich gelesen habe, dass die 'map()' Funktion von 'Pool' etwas intelligent auf den Daten funktionieren würde, aber ich denke, dass die Segmentierung zuerst einen großen Unterschied macht. Gibt es eine andere Möglichkeit, den Overhead der Prozesse zu vermeiden, die über die Daten kopieren? Erwarten Sie einen Leistungsunterschied, wenn ich 'math.sin()' stattdessen benutze? – user1475412

+0

Ich probierte 'math.sin' und naja, es war viel langsamer, sogar Multithread, dann single threaded numpy.sin, obwohl es schneller war (nahm' 6.435199's als das Multithread 'numpy.sin', das' 10.5' wahrscheinlich nahm aufgrund der Tatsache, dass 'numpy.sin' mit Arrays umgehen kann, sind die' numpy' Jungs wirklich gut in Mathe;), es gibt einen Weg, 'Shared Memory' zu verwenden http://docs.python.org/library/multiprocessing .html aber bitte nicht dessen recht gefährlich und hat nur eingeschränkte Unterstützung, oder zumindest vorsichtig treten. –

+0

Wenn Ihr nur liest, dann ist es vielleicht sicher, der Unterprozess muss nur den entsprechenden Index oder Teilmenge von Indizes verfolgen ... –

Verwandte Themen