2016-07-15 19 views
2

Gestern fragte ich eine Frage: Reading data in parallel with multiprocessein Wörterbuch parallel Multiprozessing

Ich habe sehr gute Antworten, und ich implementiert die Lösung in der Antwort erwähnt i markiert als korrekt.

def read_energies(motif): 
    os.chdir("blabla/working_directory") 
    complx_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    lig_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    return motif, complx_ener, lig_ener 

COMPLEX_ENERGIS = {} 
LIGAND_ENERGIES = {} 
p = multiprocessing.Pool(processes=CPU) 
for x in p.imap_unordered(read_energies, peptide_kd.keys()): 
    COMPLEX_ENERGIS[x[0]] = x[1] 
    LIGAND_ENERGIES[x[0]] = x[2] 

jedoch nimmt diese Lösung die gleiche Menge an Zeit, als ob ich gerade über laufen würde peptide_kd.keys() und füllen Sie das DataFrames eins nach dem anderen. Warum ist das so? Gibt es eine Möglichkeit, die gewünschten Diktate parallel zu füllen und tatsächlich eine Geschwindigkeitssteigerung zu erreichen? Ich betreibe es auf einem 48-Core-HPC.

+0

Es kann sein, dass der Overhead der Verwendung von Multiprocessing größer als der der komplexen Funktionsverarbeitung ist. Vielleicht, wenn 'read_energies()' jedes Mal ein Datenfeld mit einer variablen Anzahl verarbeiten würde, würde es Ihnen ermöglichen, die Dinge auf den Punkt abzustimmen, wo es vorteilhaft wurde. – martineau

Antwort

3

In (1) starten Sie jeden Prozess und (2) müssen Sie die pandas.DataFrame (und usw.) über mehrere Prozesse kopieren. Wenn Sie nur eine dict parallel gefüllt haben, würde ich vorschlagen, einen gemeinsamen Speicher dict zu verwenden. Wenn kein Schlüssel überschrieben wird, ist es einfach und Sie müssen sich nicht um Sperren kümmern.

(Anmerkung I multiprocess unten bin mit, die eine Gabel von multiprocessing ist - aber nur so kann ich von dem Dolmetscher demonstrieren, sonst würden Sie die unten von __main__ zu tun haben).

>>> from multiprocess import Process, Manager 
>>> 
>>> def f(d, x): 
... d[x] = x**2 
... 
>>> manager = Manager() 
>>> d = manager.dict() 
>>> job = [Process(target=f, args=(d, i)) for i in range(5)] 
>>> _ = [p.start() for p in job] 
>>> _ = [p.join() for p in job] 
>>> print d 
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 

Diese Lösung nicht Kopien der dict über Prozesse zu teilen, so dass ein Teil des Overhead reduziert wird. Für große Objekte wie ein pandas.DataFrame kann es im Vergleich zu den Kosten einer einfachen Operation wie x**2 von Bedeutung sein. In ähnlicher Weise kann das Laichen einer Process Zeit in Anspruch nehmen, und Sie können die oben genannten sogar noch schneller (für leichte Objekte) mit Threads (d. H. Von multiprocess.dummy anstelle von multiprocess für entweder Ihre ursprünglich veröffentlichte Lösung oder meine oben).

Wenn Sie Notwendigkeit tun DataFrames zu teilen (wie Ihr Code schlägt vor, statt wie die Frage stellt), könnten Sie in der Lage sein, es zu tun, indem numpy.ndarray einen gemeinsamen Speicher zu schaffen.

+0

Danke für die Antwort! Ich werde es jetzt versuchen, aber zuerst möchte ich etwas fragen. Ich verstehe den Unterschied zwischen den erwähnten 'shared' Datenrahmen (Variablen schätze ich nicht). Warum bedeutet mein Code, dass ich einen freigegebenen Dataframe verwende? Der Job, den ich parallel machen möchte, ist wie beschrieben, füllt ein Wörterbuch auf und benutzt es anschließend auf verschiedene Arten (lies die darin enthaltenen Daten), aber ändere nichts darin. –

+0

Der Grund, warum ich gesagt habe, dass Sie Shared-Memory-Arrays untersuchen könnten, ist, dass Sie zwei "DataFrame" -Instanzen von jedem "Process" zurückgeben. Es ist jedoch schwierig, Sie darauf hinzuweisen, ob Sie dies tun müssen oder nicht, da Sie nur Meta-Code präsentiert haben. –

+0

Ohh ich sehe. Ich brauche beide 'DataFrames'. Ist es problematisch, zwei von ihnen zurückzugeben? Wäre es einfacher, dies in zwei separaten Schritten zu tun? –