2010-12-01 14 views
2

Ich versuche jetzt, die Leistung einer Winform-Anwendung zu verbessern, indem Sie es multi-threaded machen. Derzeit sieht die Klasse wie:Verbessern Sie die Leistung durch Multithreading

public class MainClass 
{ 
    List<DataItem> data; //thousands of DataItem, but each is independent 

    //and a lot of non-thread-safe variables here,variable1 variable2 ... 

    public void Go() 
    { 
     data.ForEach(item => DealWithDataItem(item)); 
    } 

    public void DealWithDataItem(DataItem item) 
    { 
     //costs really long time here 
     Step1(item); 
     Step2(item); //and a lot of StepN(item) 
    } 

    public void StepN(DataItem item) 
    { 
     //variable1 = blabla 
     //variable2 = blabla ..etc 
    } 
} 

I ThreadPool für jede DataItem verwenden möchten.

data.ForEach(item => ThreadPool.QueueUserWorkItem(s => DealWithDataItem(item))); 

Aber so viele nicht Thread-sichere Variablen! Ich kann sie nicht in einer Methode deklarieren, weil sie zwischen den Methoden StepN geteilt wird. Und es ist ziemlich schwer, sie alle threadsicher zu machen! Mache ich etwas falsch? Irgendwelche guten Lösungen? Vielen Dank!

+0

ist kein Hintergrundarbeiter ausreichend? –

+1

Es hängt wirklich davon ab, was Sie mit Ihren Variablen tun1..n summieren sie Werte? Liest du? Schreiben? Sie müssen viel genauer über die Verwendung dieser Variablen sein. Für unterschiedliche Nutzungsmuster gibt es unterschiedliche Lösungen. –

+0

Verstehe nicht ganz.Ist 'MainClass' eine Art Monitor für den Gesamtfortschritt beim Umgang mit' DataItem'-Fortschritt (also benötigt man sie als Status für 'MainClass'). Wenn nicht, sollten Sie separate Objekte für jede Ihrer Arbeiten erstellen. –

Antwort

3

Versuchen Sie mit ParallelEnumerable.AsParallel.

data.AsParallel.ForEach(DoWork); 

Es werden automatisch Threads abhängig von der Anzahl der Prozessoren/Kerne erstellt. Das einzige Problem, dass es in Framework 4.0 enthalten ist. Weitere Informationen über PLINQ. (Und wie andras kommentiert: für framwork 3.5 es verfügbar ist als Stand-alone Reactive Extensions (Rx))

UPD: als 0xA3 sagte Refaktorierungscode, jedes Element zu machen haben sie eigene calc Variablen ist dringend empfohlen. Ich empfehle Ihnen, Berechnungslogiken zu DataItem

zu extrahieren Oder spezielle Klasse wie "Calculator" zu erstellen, die die ganze Arbeit tun würde, so würde DataItem nur Daten speichern, und Logiken von Berechnungen würden in Rechner Klasse enthalten sein.

data.AsParallel.ForEach(x=> new Calculator().DoWork(x)); 

wo Calculator-Klasse ist so etwas wie dieser

class Calculator 
{ 
    // variables here 

    void DoWork(DataItem item) 
    { 
    Step1(item); 
    Step2(item); 
    // ... 
    // StepN(item); 
    } 
} 
+0

'Parallel.ForEach' und viele andere Dinge können für .NET 3.5 in der Rx-Bibliothek gefunden werden . http://codeblog.theg2.net/2010/02/tpl-and-parallelforeach-in-net-35-using.html –

+0

@andras Danke, wird die Antwort aktualisieren –

0

wahrscheinlich der beste Weg wäre, um Ihren Code Refactoring, so dass Sie alle loszuwerden, die zwischen den verschiedenen Datenelementen gemeinsam genutzten Feldern.

ändern (oder Unterklasse) der DataItem Klasse enthält alle relevanten Daten und Methoden für eine dataItem Manipulation, so dass Ihr Code Änderungen an etwas wie folgt aus:

public void DealWithDataItem(DataItem item) 
{ 
    item.Step1(); // does not change the state of `this` 
        // and only changes variables that are private to `item` 
    item.Step2(); // and a lot of StepN(item) 
} 
0

Da jeder DataItem unabhängig ist, die bewegen Arbeit in eine neue DataItem Arbeiter Methode, und lassen Sie jede Instanz beschäftigen sich mit sich selbst:

public class MainClass 
{ 
    List<DataItem> data; //thousands of DataItem, but each is independent 

    public void Go() 
    { 
     data.ForEach(item => ThreadPool.QueueUserWorkItem(s => s.DealWithSelf())); 
    } 
} 

public class DataItem 
{ 
    //and a lot of non-thread-safe variables here,variable1 variable2 ... 

    void DealWithSelf() 
    { 
     //costs really long time here 
     Step1(item); 
     Step2(item); //and a lot of StepN(item) 
    } 

    public void StepN(DataItem item) 
    { 
     //variable1 = blabla 
     //variable2 = blabla ..etc 
    } 
} 
0

Ist MainClass in Ihrem GUI-Thread? Sie sollten keine Datenverarbeitung in Ihrem GUI-Thread durchführen. Führen Sie MainClass in einem separaten Thread aus.

Wie geht das? Das hängt ganz von den blabla Sachen ab, die Sie uns nicht gezeigt haben. Muss MainClass ein Ergebnis zurückgeben? Verwenden Sie BeginInvoke/EndInvoke. Müssen Sie die GUI aktualisieren? Verwenden Sie BackgroundWorker. Wenn Sie eine bessere Antwort wünschen, müssen Sie uns mehr Informationen geben.

Verwandte Themen