Wielowątkowość(pętle, Task) w C# 4.0

Programowanie współbieżne w c# 4.0 jest znacznie łatwiejsze w porównaniu z poprzednią wersją. Widać, że platforma .NET staje się coraz dogodniejszym środowiskiem programistycznym dla rozwiązań równoległych.

Zacznijmy od pętli foreach. Przeważnie wykonujemy ją w sposób sekwencyjny. Jeśli chcielibyśmy zrównoleglić ją, musielibyśmy stworzyć instancję Thread i zawartość pętli umieścić w wątkach. Ponadto proces wymagałby użycia np. semafora albo ManualResetEvent aby zsynchronizować kod wykonywany po zakończeniu pętli. Na szczęście w wersji 4.0 mamy do dyspozycji gotowy mechanizm:

string []tab=new string[]{"a","b","c","d","e"};
System.Threading.Tasks.Parallel.ForEach<string>(tab, Method);

gdzie Method:

private static void Method(string val)
{
}

Pętla zostanie wykonana w sposób równoległy. Jeśli tylko nie współdzielimy jakiego stanu pomiędzy kolejnymi iteracjami, warto zastanowić się nad tym typem pętli,  ponieważ jest to bardzo proste a na procesorach wielordzeniowych wzrost wydajności może być znaczący.

Nową klasą w C# 4.0 jest System.Threading.Tasks.Task. Umożliwia ona wykonanie operacji w tle(w osobnym wątku). Warto podkreślić, że Task bazuje na ulepszonym ThreadPool, zatem wydajność tworzenia nowego Task’a jest dużo wyższa niż w przypadku “ciężkiego” Thread. Samo stworzenie Task’a jest analogiczne do Thread:

  Task t1 = new Task(() => Console.Write("task 1"));
  t1.Start();    

Możemy również poczekać aż task zostanie wykonany:

Task t1 = new Task(() => Console.Write("task 1"));
t1.Start();
t1.Wait();

Ciekawszym jednak rozwiązaniem jest tzw. kontynuacja zadań. Możemy stworzyć listę zadań, które będą wykonywały się po kolei. Często mamy przecież problemy współbieżne w których wykonanie kolejnego etapu musi być poprzedzone zakończeniem poprzedniego. Za pomocą ContinueWith możemy w łatwy sposób stworzyć taki plan wykonania:

Task t1 = new Task(delegate()
 {                    
     Console.Write("task 1");
     Thread.Sleep(5000);
 }
);
Task t2 = t1.ContinueWith((t) => Console.Write("task 2"));
t1.Start();
t2.Wait();

Powyższy kod gwarantuje, że zadanie t2 zostanie wykonane dopiero po zakończeniu t1.

Leave a Reply

Your email address will not be published.