2015-12-25 6 views
9

Ich habe ein Array x [] mit Daten. Außerdem gibt es eine Reihe von "Systemzuständen" c []. Der Prozess:Synchroner paralleler Prozess in C#/C++

for(i = 1; i < N; i++) 
{ 
    a = f1(x[i] + c[i-1]); 
    b = f2(x[i] + c[i-1]); 
    c[i] = a + b; 
} 

Gibt es eine effiziente Möglichkeit, die Werte von f1 und f2 auf 2-Core-System mit zwei parallelen Threads zu finden? Ich meine die folgenden (in Pseudocode):

thread_1 
{ 
    for(i = 1; i < N; i++) 
     a = f1(x[i] + c[i-1]);  
} 
thread_2 
{ 
    for(i = 1; i < N; i++) 
    { 
     b = f2(x[i] + c[i-1]); 
     c[i] = a + b; //here we somehow get a{i} from thread_1 
    } 
} 

f1 und f2 keine Zeit consumptive sind, müssen aber oft berechnet werden, so gewünschte Beschleunigung über x2 ist. Siehe Diagramm zur grafischen Darstellung:

desired parallel process

der Suche nach Code-Beispiele für Windows.

+1

Es wird nur efficien sein, wenn f1 und f2 sehr havy und syncronization overhead weniger als Gewinn von parallelem Lauf sind – gabba

+0

Warum ist dies markiert C# ** und ** C++? Welche Sprache verwendest du? –

+0

Die Auswahl der Sprache hängt davon ab, was die Aufgabe effizienter lösen kann. – carimus

Antwort

4

Wenn ich Sie recht verstehe,

  • a[i] kann nur berechnet werden, wenn c[i-1] verfügbar ist
  • b[i] kann nur berechnet werden, wenn c[i-1] verfügbar ist
  • c[i] ist nur verfügbar, wenn a[i] und b[i] berechnet werden

Es bedeutet, dass der einzige Prozess, den Sie separat durchführen können, a[i] und b[i] ist.

Das ist, wie ich es in C# zu sehen:

for (int i = 1; i < N; i++) 
{ 
    Task<double> calcA = Task.Factory.StartNew(() => { return f1(x[i] + c[i-1]); }); 
    Task<double> calcB = Task.Factory.StartNew(() => { return f2(x[i] + c[i-1]); }); 

    // .Result will block the execution and wait for both calculations to complete 
    c[i] = calcA.Result + calcB.Result; 
} 

Dies wird zwei separate Threads laufen, die jeweils f1 und f2 berechnen wird. Nachdem sowohl f1 als auch f2 berechnet wurden, wird der Wert c[i] gesetzt und die nächste Iteration ausgeführt.

Beachten Sie, dass:

  • ich double verwenden, vorausgesetzt, dass Ihr f1 und f2 Rückkehr double
  • Die Schleife von 1 beginnt, unter der Annahme, dass Sie einige erste a[0] und b[0] Werte haben. Andernfalls würde c[i-1] eine Ausnahme werfen
  • Dies wird nur Verbesserung bringen, wenn die Berechnung der f1 und f2 wirklich ist ressourcenaufwändig und lang, im Vergleich zu anderen Berechnungen
  • Task.Factory.StartNew (im Gegensatz zu Thread verwendet) Threadpool verwendet, was bedeutet, dass es doesn‘ t erstellt jedes Mal einen neuen Thread, verwendet aber das vorhandene aus dem Pool erneut. Es reduziert spürbar den Overhead.
+0

Dies funktioniert nicht korrekt, da die Schleifenvariable beim Schließen verwendet wird. Sie müssen eine lokale Kopie erstellen – VMAtm

+0

@VMAtm Da die Aufgabe innerhalb der gleichen Schleifeniteration deklariert, ausgeführt und beendet wird, sehe ich keine Möglichkeit der 'i'-Modifikation. Ich kann mich natürlich irren ... –

+1

Es wird nur dann efficien, wenn f1 und f2 sehr havy und syncronization overhead weniger als der Gewinn von parallelem Lauf sind – gabba

3

Der einzige parallele Teil in diesem Algorithmus Berechnung von f1 und f2 ist, aber Sie sagen, dass f1 und f2 nicht consumptive Zeit, so Es könnte viel besser sein, die SIMD-Vektorisierung (z. B. System.Numerics.Vectors in C#) zu verwenden und sie auf einem Kern auszuführen (wodurch auch Cache-Fehler verringert werden). Oder wahrscheinlich könnten Sie Ihren Algorithmus ändern, um parallelisiert zu werden (aber es könnte harte Arbeit erfordern).