2009-08-18 7 views
3

im folgenden Ausschnitt, wenn Sie Do durch ParallelDo ersetzen, wird es um einen Faktor von 3 SLOWER bewerten, weil jetzt die Schleife in nur einem der beiden Kernel gebrochen wird.Wie brechen Sie aus parallelen Schleifen aus? ParallelBreak

ParallelEvaluate[NN = 10070]; 
SetSharedVariable[res] 
Module[{a, b, c}, 
    Do[ 
    c = NN - a - b; 
    If[a a + b b == c c, res = a b c; Break[]] 
    , {a, 1, NN}, {b, a + 1, NN} 
    ]; 
    res 
    ] // AbsoluteTiming 

Calling ParallelAbort würde das Problem lösen, aber es ist verboten. Was gibt es noch?

Antwort

3

Sie müssen für jede Iteration einen Weg haben, um alle anderen Iterationen, bei denen die Antwort gefunden wurde, über zu informieren. Ich modellierte dies mit einem "quit" -Flag, ursprünglich gesetzt auf false, das ist auf wahr gesetzt, wenn eine Iteration beschließt zu beenden. Jede Iteration hat ebenfalls , um die Ausgangsbedingung zu überprüfen.

Mein Mathematica ist 15 Jahre rostig, und ich habe nicht die Formen vor Parallelxxx gesehen, aber eine gute Vermutung , wie die Schleife ändern sollte, ist die folgende Variante Code:

ParallelEvaluate[NN = 10070]; 
SetSharedVariable[res,quit] 
Module[{a, b, c}, 
    quit=false; 
    Do[ c = NN - a - b; 
     If[quit, Break[]]; 
     If[ a a + b b == c c, quit=true; res = a b c; Break[]], 
     {a, 1, NN}, {b, a + 1, NN} 
    ]; 
    res 
    ] // AbsoluteTiming 

Das Extra If verlangsamt die Schleife etwas, aber das ist der Preis von Synchronisation.

Ich vermute, dass die Menge der Arbeit, die Sie in jeder Iteration tun schon ziemlich klein ist im Vergleich zu den Kosten für jede Iteration in parallel ausgeführt wird, so diese Schleife wahrscheinlich ineffizient ist und Sie können nicht einen wirklichen Wert erhalten von der Do Parallel. Wenn nicht, dann können Sie jede Do-Iteration auf mehrere Werte von a und b anwenden (z. B. {a, 1, NN, 10} und ähnlich für b für jede Iteration und den 10-breiten Teilbereich als eine Subloop innerhalb jeder parallelen Iteration). zu halten die Quit-Test Exit Overhead klein im Vergleich auf die Arbeit in jedem Körper der Schleife. Übung für den Leser erneut rekodieren.

Ihr Code hat ein anderes Problem: Es gibt eine Wettlaufsituation in der Einstellung res. Unter bestimmten Umständen könnten zwei Iterationen beide entscheiden, res einzustellen. Wenn Sie sich nicht interessieren, welche Antwort produziert wird, und der Speicher zu res ist "atomare", ist das in Ordnung. Wenn res eine kompliziertere Datenstruktur wäre, und die Aktualisierung mehrere Mathematica-Anweisungen dauerte, hätten Sie sicherlich ein Datenrennen und Ihre Schleife würde einmal in großer Zeit schlechte Ergebnisse produzieren und es wäre sehr schwer zu debuggen. Sie benötigen idealerweise eine Art atomaren Test, um die Ausgangsbedingung zu schützen. Ich weiß nicht, was das ist in MMa, , so dass Sie nachsehen müssen, aber ich stelle mir eine "atomare [...]" Form vor, die darauf besteht, dass ihr Körper nur von einem der vielen parallelen Threads ausgeführt wird . . (Vielleicht MMa hat ein Semaphore, die Sie] Atom implementieren können Wenn ja, sollten Sie den Code dann wie folgt aussehen:

ParallelEvaluate[NN = 10070]; 
SetSharedVariable[res,quit] 
Module[{a, b, c}, 
    quit=false; 
    Do[ c = NN - a - b; 
     If[quit, Break[]]; 
     If[ a a + b b == c c, 
      atomic[If[not[quit]; quit=true; res = a b c;]; Break[]], 
     {a, 1, NN}, {b, a + 1, NN} 
    ]; 
    res 
    ] // AbsoluteTiming 
+1

Die nächste Sache Mathematica hat Atomcritical genannt wird, mit dem Sie festlegen können nach oben sperren. – Pillsy

Verwandte Themen