wtorek, 19 lutego 2013

[C#|Visual Studio] Threading: Tasks

Task to obiekt reprezentujący pewnną jednostkę pracy (fragment kodu), którą chcemy zrównoleglić. Korzysta on z puli wątków, co poprawia wydajność w stosunku do wątków uruchamianych przez klasę Thread. Głównym zadaniem Tasków jest optymalne wykorzystanie wielordzeniowości komputera, przy niskich kosztach pamięciowych zrównoleglania (możemy dodawać do puli wątków setki zadań, które zostaną wykonywane w najszybszy możliwy sposób). Co więcej wprowadzają kilka zupełnie nowych, bardzo ciekawych funkcjonalności, takich jak na przykład możliwość uruchamiania child - Tasków z poziomu danego Tasku.

Operacje poprzez Taski można wykonywać na kilka sposobów:

static void RunTasks()
{
    //1 delegate
    Task.Factory.StartNew(() => Console.WriteLine("Hello from a task!"));
    //2 Task<T> - return value
    Task<string> task = Task.Factory.StartNew<string>(() =>
    {
        using (var wc = new System.Net.WebClient())
            return wc.DownloadString("http://www.agh.edu.pl");
    });
    //3 constructor
    var task2 = new Task(() => Console.Write("Hello"));
    //wait for result
    Console.WriteLine(task.Result);
    task2.Start();
    //4 state object
    var task3 = Task.Factory.StartNew (Greet, "Hello");
    task3.Wait();  // Wait for task to complete.   
}

static void Greet (object state) { Console.Write (state); }

Startowanie child-Tasków:

Task parent = Task.Factory.StartNew(() =>
{
    Console.WriteLine("I am a parent");

    Task.Factory.StartNew(() =>
    {
        Console.WriteLine("I am detached");
    });

    Task.Factory.StartNew(() =>
    {
        Console.WriteLine("I am a child");
    }, TaskCreationOptions.AttachedToParent);
});

Dzięki opcji AttachedToParent, aby parent mógł zakończyć swoje zadanie, będzie musiał poczekać na wykonania childa z tą właśnie opcją.

Synchronizację z Taskami można wykonać na dwa sposoby: wywołując metodę Wait() z opcjonalnym timeoutem, lub pobierając wartość property Result. W obu przypadkach program musi zaczekać na zakończenie działania Tasków.

Wyjątki:

Wyjątki w kodzie Tasków są propagowane do wątku wywołującego taski i opakowane w specjalną klasę AggregateException.

static void ExceptionTest()
{
    int x = 0;
    Task<int> calc = Task.Factory.StartNew(() => 7 / x);
    try
    {
        Console.WriteLine(calc.Result);
    }
    catch (AggregateException aex)
    {
        Console.Write(aex.InnerException.Message);  // Attempted to divide by zero
    }
}

Wyjątki z child-Tasków propagowane są do parent Tasków.

Continuation

Metoda ContinueWith z klasy Task pozwala na wykonywanie podanego delegata po zakończeniu działania zadania.

Task task1 = Task.Factory.StartNew(() => Console.Write("antecedant.."));
Task task2 = task1.ContinueWith(ant => Console.Write("..continuation"));

Synchronizować można się także z wieloma Taskami stosując ContinueWithAll bądź ContinueWithAny.
 

Brak komentarzy:

Prześlij komentarz