Маніпуляція завданнями (Task) в Task Parallel Library

Доброго вечора!! Я все таки розібрався з форматуванням коду на моєму блозі, і пере форматував всі попередні статті :). Тому, хто не міг читати їх через жахливе форматування, тепер можете сміливо приступати.

Сьогодні я напишу коротеньку статтю, яка знову буде відноситись до серії з статей по паралельному програмуванню в .NET Framework 4.0. Після закінчення написання цих статей, я складу структурований список, який дозволить вам вивчати Task Parallel Libraryта й взагалі паралельне програмування поступово.

Створення послідовних завдань

При реалізації якоїсь функціональності, вам скоріш за все попадеться ситуація, в якій певну роботу треба запускати лише після того як виконається інша робота. Для реалізації таких механізмів, TPLпропонує нам наступні екземплярні методи класу Task:

· Task<T>ContinueWith

· Task.ContinueWith

Ось як вони працюють на прикладі:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TPLContinuation
{
     class Program
     {
         static void Main(string[] args)
         {
              Task<Double> firstTask = new Task<Double>(() =>
              {
                  return Math.Pow(10, 2);
              });
              Task secondTask = firstTask.ContinueWith(prevTask =>
              {
                   Console.WriteLine("Your result is: {0}", prevTask.Result);
              });
              firstTask.Start();
              Console.ReadLine();
         }
     }
}

В цьому коді я створюю перший екземпляр класу Task<T> з типом Double, який визначає тип результату, який буде отриманий при його завершені, і передаю в нього анонімний метод (делегат), який має виконатись при запуску завдання. Як ви бачите, цей метод просто підносить 10 до 2-ї степені та повертає результат. Наступним кроком я створюю інший екземпляр класу Task, через екземпляр ний метод ContinueWith попереднього об’єкту Task, в який знову таки передаю анонімний метод (делегат), який має виконатись після завершення першого завдання.

Як видно в коді, до результату попереднього завдання, в анонімному методі я можу доступатись через властивість Result класу Task, який передається як параметр в цей метод:

Task secondTask = firstTask.ContinueWith(prevTask =>
{
    Console.WriteLine("Your result is: {0}", prevTask.Result);
});

Отже використовуючи ці методи, ми маємо можливість побудувати цілу послідовність завдань, які будуть виконуватись один за одним.

Створення вкладеного завдання

Ми також можемо створювати вкладені завдання, які будуть запускатись в коді попереднього (батьківського) завдання:

static void Main(string[] args)
{
    Task firstTask = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("First task started");
        Task secondTask = Task.Factory.StartNew(() =>
        {
             Console.WriteLine("Child task completed");
        });
    });
        firstTask.Wait();
        Console.WriteLine("First task completed");
        Console.ReadLine();
}

В цьому коді, головне завдання, в якому запускається інше, вкладене завдання, не чекає на завершення виконання цього вкладеного завдання, тому результат виконання буде таким:

Ми це можемо змінити, передавши другим параметром в конструктор класу Task значення AttachedToParent, з перечислення доступних значень TaskCreationOptions

static void Main(string[] args)
{
    Task firstTask = Task.Factory.StartNew(() =>
    {
         Console.WriteLine("First task started");
         Task secondTask = Task.Factory.StartNew(() =>
         {
             Console.WriteLine("Child task completed");
         }, TaskCreationOptions.AttachedToParent);
    });
    firstTask.Wait();
    Console.WriteLine("First task completed");
    Console.ReadLine();
}

При виконанні цього коду, результат буде таким:

Очікування завершення завдань

Використовуючи статичний метод WaitAll класу Task, розробник може призупинити потік виконання, доки всі екземпляри завдань, які були передані в цей метод не будуть завершені:

static void Main(string[] args)
{
    Task[] tasks =
    {
        Task.Factory.StartNew(() =>
        {
             Console.WriteLine("Execution of the first task..");
        }),
        Task.Factory.StartNew(() =>
        {
             Console.WriteLine("Execution of the second task..");
        })
    };
    Task.WaitAll(tasks);
    //Потік зупинився, доки всі завдання не будуть виконані..
    Console.WriteLine("First task completed");
    Console.ReadLine();
}

Також в цього метода є перевантаження, яке приймає кількість Int32(число), яке визначає максимальну кількість мілісекунд, на які потік може призупинитись.

На сьогодні достатньо інформації щодо паралельного програмування, буду старатись по частіше викладати сюди матеріали, так що заходьте сюди частіше.

Advertisements

, , ,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: