2010-09-15 32 views
7

Niedawno przeniosłem się do C# .net 4.Kiedy używać Parallel.For?

Kocham Parallel.For, ale nie wiem kiedy i kiedy nie używać. Wiem, że jeśli zamówienie nie jest dla mnie ważne - użyję go.

Ale czy są jakieś testy dotyczące kosztów pracy z Parallels? Znaczenie: jeśli moja pętla działa tylko 10 razy (i wykonuje bardzo mało logiki) - czy powinienem unikać Parallels? Czy są jakieś reguły kciuka?

+0

Tutaj jest naprawdę dobry darmowy ebook z Microsoft, który obejmuje ten temat " [Wzory programowania równoległego: Rozumienie i stosowanie równoległych wzorców w środowisku .NET Framework 4] (https://www.microsoft.com/en-us/download/details.aspx?id=19222) " –

Odpowiedz

4

Unikałbym używania Parallel.For, chyba że wydajność jest problem.

Pisanie kodu uruchamianego jednocześnie jest ogólnie trudniejsze niż pisanie kodu z pojedynczym gwintem. Ponadto jeśli popełnisz błąd z powodu problemu z współbieżnością, może być trudno go debugować. Na przykład błąd może wystąpić tylko czasami i nie może być łatwo odtwarzalny. Jeśli nie masz konkretnej potrzeby zwiększenia wydajności, sugerowałbym, abyś był prosty i używał zwykłej pętli w jednym wątku.

+0

Zgadzam się - nie" po prostu go używaj, ponieważ jest tam , spróbuj rozwiązać rzeczywisty problem z tym. Poza tym profilowanie jest twoim przyjacielem;) –

+0

Myślę, że "domniemanie było problemem". –

+0

Zgadzam się z Markiem. Użyj najmniej dostępnych zasobów dla zadania. – Josh

0

Cytując pytania SQLite: "Threads are evil. Unikaj ich "paralelizacji" przydaje się do wydajności. Optymalizacja wydajności aplikacji jest jedną z najbardziej kontrowersyjnych rzeczy w projektowaniu oprogramowania i powinna być wykonana z najwyższą ostrożnością, przy użyciu odpowiednich narzędzi pomiarowych, lub będzie wyglądać śmiesznie.

Niektórzy mogą zoptymalizować kod UI tak, aby odpowiadał w ciągu mikrosekund zamiast milisekund, wyraźnie nie mając żadnej wartości i powodując wiele uszkodzeń.

+0

Pewna prawda w tym, ale w sumie zbyt prosta. Zobacz na przykład http: // stackoverflow.com/questions/3415519/is-there-a-point-to-multithreading/3415563 # 3415563 –

1

Pętla Parallel.For używa ThreadPool do wykonania pracy w pętli poprzez wywołanie delegata raz na każdą iterację pętli.

Ogólna idea jak Parallel.For prace można przedstawić w następujący sposób:

public static void MyParallelFor(int inclusiveLowerBound, int exclusiveUpperBound, Action<int> body) 
{ 
    // Get the number of processors, initialize the number of remaining 
    // threads, and set the starting point for the iteration. 
    int numProcs = Environment.ProcessorCount; 
    int remainingWorkItems = numProcs; 
    int nextIteration = inclusiveLowerBound; 
    using (ManualResetEvent mre = new ManualResetEvent(false)) 
    { 
     // Create each of the work items. 
     for (int p = 0; p < numProcs; p++) 
     { 
      ThreadPool.QueueUserWorkItem(delegate 
      { 
       int index; 
       while ((index = Interlocked.Increment(ref nextIteration) - 1) < exclusiveUpperBound) 
        body(index); 

       if (Interlocked.Decrement(ref remainingWorkItems) == 0) 
        mre.Set(); 
      }); 
     } 
     // Wait for all threads to complete. 
     mre.WaitOne(); 
    } 
} 

Parallel.For zwraca ParallelLoopResult typ wartości, która zawiera szczegółowe informacje na temat zakończonej pętlą. Jednym z jego przeciążeń jest:

public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body); 

Ważne jest, aby zdać sobie sprawę, że wykonanie równoległe nie zawsze jest szybsze niż wykonanie seryjne. Aby zdecydować, czy używać równolegle, czy nie, musisz oszacować nakład pracy, który będzie wykonywany w przeliczeniu na pętlę. Jeśli rzeczywista praca wykonywana przez pętlę jest niewielka w stosunku do kosztu synchronizacji wątku, lepiej użyć zwykłej pętli.

Jest to jeden przykład, kiedy seryjny do wykonywania pętli jest szybsza, że ​​równolegle:

static void Main(string[] args) 
{ 
    Action<int> action = new Action<int>(SimpleMethod); 

    // ordinary For loop performance estimation 
    var sw = Stopwatch.StartNew(); 

    for(int i = 0; i < 1000; i++) 
     action(i); 

    Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds); 

    // parallel For loop performance estimation 
    sw = Stopwatch.StartNew(); 

    Parallel.For(0, 1000, action); 

    Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds); 
} 

static void SimpleMethod(int index) 
{ 
    int d = 1; 
    int result = index/d; 
} 

wyjściowa:

0.0001963 sec. 
0.0346729 sec.