niedziela, 17 lutego 2013

[C#|Visual Studio] Threading: PLINQ

.NET Framework w wersji 4.0 udostępnił programistom nową bibliotekę - PFX (Parallel Framework). Wprowadza ona nową jakość w programowaniu wielowątkowym. Jednym z najważniejszych osiągnięć PFX jest PLINQ - mechanizm oferujący automatyzację wszystkich kroków w zrównoleglaniu obliczeń. Kroki te to:
  • podział zadań na Taski 
  • wykonywanie Tasków na wątkach
  • zebranie wszystkich wyników w całość
Parallel LINQ to zatem nic innego, jak równoległa implementacja dobrze znanego LINQ to objects. Kluczem do użycia PLINQ jest specjalna metoda AsParallel(). To dzięki niej, w sposób deklaratywny programista wprowadza zrównoleglenie obliczeń. Prosty przykład to poszukiwanie liczb pierwszych, gdzie podczas filtrowania wykonuje się proste operacje matematyczne.

static void PrimeNumbers()
{
    IEnumerable<int> numbers = Enumerable.Range(3, 100000 - 3);

    var parallelQuery =
      from n in numbers.AsParallel()
      where Enumerable.Range(2, (int)Math.Sqrt(n)).All(i => n % i > 0)
      select n;

    int[] primes = parallelQuery.ToArray();
    foreach (var prime in primes)
    {
        Console.Write("{0} ", prime);
    }
}

Zapytania PLINQ, podobnie jak każde inne LINQ są wykonywane z opóźnieniem, w momencie, gdy np. wywołamy ToArray, pętlę foreach itd. Równoległość obliczeń powoduje jednak, że wyniki będą nieuporządkowane. Jeżeli zależy nam na tym, by wynik wyglądał tak, jak w sekwencyjnym zapytaniu, możemy dodatkowo wywołać metodę AsOrdered()

from n in numbers.AsParallel().AsOrdered()

Wywołania takie wpływa oczywiście na pogorszenie wydajności, dlatego takie zachowanie nie pojawia się domyślnie.

PLINQ optymalizuje zrównoleglenie pod kątem możliwości sprzętowych. To jedna z największych zalet zwłaszcza pod kątem przyszłości, gdzie liczba rdzeni w komputerach PC będzie ciągle wzrastać. W przypadku niektórych komputerów, PLINQ może wykonać obliczenia sekwencyjnie pomimo użycia AsParallel(), np. dlatego, że zrównoleglenie może pogorszyć wydajność. Programista ma możliwość wymuszenia równoległości instrukcją

from n in numbers.AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism)

Kolejną ciekawą instrukcją jest WithDegreeOfParallelism(), gdzie podajemy ilość Tasków, na których ma być przetwarzane zapytanie. Szczególnie przydatne jest to w przypadku odpytywania WebSerwisów, gdzie tracimy czas nie na obliczeniach na CPU, ale na oczekiwaniu na odpowiedź.

from n in numbers.AsParallel().WithDegreeOfParallelism(6)

Brak komentarzy:

Prześlij komentarz