В основе библиотеки TPL лежит концепция задач, каждая из которых описывает отдельную продолжительную операцию. В библиотеке классов .NET задача представлена специальным классом – классом Task, который находится в пространстве имен System.Threading.Tasks. Данный класс описывает отдельную задачу, которая запускается асинхронно в одном из потоков из пула потоков. Хотя ее также можно запускать синхронно в текущем потоке. Однако в любом случае следует отметить, что задача – это не поток.
Для определения и запуска задачи можно использовать 3 способа.
// Первый способ создание объекта Task и вызов у него метода Start:
// В качестве параметра Task принимает делегат Action, то есть мы можем передать любое действие,
// например, лямбда-выражение, как в данном случае, или ссылку на какой-либо метод
Task task1 = new Task(() => Console.WriteLine("Task1 is executed"));
task1.Start();
// Второй способ использование статического метода Task.Factory.StartNew().
// метод сразу запускает задачу:
Task task2 = Task.Factory.StartNew(() => Console.WriteLine("Task2 is executed"));
// Третий способ определения и запуска задач
// представляет использование статического метода Task.Run():
Task task3 = Task.Run(() => Console.WriteLine("Task3 is executed"));Задачи не выполняются последовательно. Первая запущенная задача может завершить свое выполнение после последней задачи.
Чтобы приложение ожидало завершения задачи, можно использовать метод Wait() объекта Task.
Стоит отметить, что метод Wait() блокирует вызывающий поток, в котором запущена задача, пока эта задача не завершит свое выполнение.
Task task1 = new Task(() => Console.WriteLine("Task1 is executed"));
task1.Start();
Task task2 = Task.Factory.StartNew(() => Console.WriteLine("Task2 is executed"));
Task task3 = Task.Run(() => Console.WriteLine("Task3 is executed"));
task1.Wait(); // ожидаем завершения задачи task1
task2.Wait(); // ожидаем завершения задачи task2
task3.Wait(); // ожидаем завершения задачи task3возможный вывод в консоль:
Task3 is executed
Task2 is executed
Task1 is executedПо умолчанию задачи запускаются асинхронно. Однако с помощью метода RunSynchronously() можно запускать синхронно:
Console.WriteLine("Main Starts");
// создаем задачу
Task task1 = new Task(() =>
{
Console.WriteLine("Task Starts");
Thread.Sleep(1000);
Console.WriteLine("Task Ends");
});
task1.RunSynchronously(); // запускаем задачу синхронно
Console.WriteLine("Main Ends"); // этот вызов ждет завершения задачи task1 Свойства класса Task
Класс Task имеет ряд свойств, с помощью которых мы можем получить информацию об объекте. Некоторые из них:
- AsyncState: возвращает объект состояния задачи
- CurrentId: возвращает идентификатор текущей задачи (статическое свойство)
- Id: возвращает идентификатор текущей задачи
- Exception: возвращает объект исключения, возникшего при выполнении задачи
- Status: возвращает статус задачи. Представляет перечисление
System.Threading.Tasks.TaskStatus, которое имеет следующие значения:Canceled: задача отмененаCreated: задача создана, но еще не запущенаFaulted: в процессе работы задачи произошло исключениеRanToCompletion: задача успешно завершенаRunning: задача запущена, но еще не завершенаWaitingForActivation: задача ожидает активации и постановки в график выполненияWaitingForChildrenToComplete: задача завершена и теперь ожидает завершения прикрепленных к ней дочерних задачWaitingToRun: задача поставлена в график выполнения, но еще не начала свое выполнение
- IsCompleted: возвращает true, если задача завершена
- IsCanceled: возвращает true, если задача была отменена
- IsFaulted: возвращает true, если задача завершилась при возникновении исключения
- IsCompletedSuccessfully: возвращает true, если задача завершилась успешно
Используем некоторые из этих свойств:
Task task1 = new Task(() =>
{
Console.WriteLine($"Task{Task.CurrentId} Starts");
Thread.Sleep(1000);
Console.WriteLine($"Task{Task.CurrentId} Ends");
});
task1.Start(); //запускаем задачу
// получаем информацию о задаче
Console.WriteLine($"task1 Id: {task1.Id}");
Console.WriteLine($"task1 is Completed: {task1.IsCompleted}");
Console.WriteLine($"task1 Status: {task1.Status}");
task1.Wait(); // ожидаем завершения задачиtask1 Id: 1
Task1 Starts
task1 is Completed: False
task1 Status: Running
Task1 Ends