Создание продолжения задачи

Одной из новаторских и очень удобных особенностей библиотеки TPL является возможность создавать продолжение задачи. Продолжение — это одна задача, которая автоматически начинается после завершения другой задачи. Создать продолжение можно, в частности, с помощью метода ContinueWith(), определенного в классе Task. Ниже приведена простейшая форма его объявления:

public Task ContinueWith(Action<Task> действие_продолженмя)

где действие_продолжения обозначает задачу, которая будет запущена на исполнение по завершении вызывающей задачи. У делегата Action имеется единственный параметр типа Task. Следовательно, вариант делегата Action, применяемого в данном методе, выглядит следующим образом.

public delegate void Action<in T>(T obj)

В данном случае обобщенный параметр Т обозначает класс Task.

Продолжение задачи демонстрируется на примере следующей программы.

// Продемонстрировать продолжение задачи.

using System;

using System.Threading;

using System.Threading.Tasks;

class ContinuationDemo {

  // Метод, исполняемый как задача,

  static void MyTask() {

    Console.WriteLine("MyTask() запущен");

    for(int count = 0; count < 5; count++) {

      Thread.Sleep(500);

      Console.WriteLine("В методе MyTask() подсчет равен " + count );

    }

    Console.WriteLine("MyTask завершен");

  }

  // Метод, исполняемый как продолжение задачи,

  static void ContTask(Task t) {

    Console.WriteLine("Продолжение запущено");

    for(int count = 0; count < 5; count++) {

      Thread.Sleep(500);

      Console.WriteLine("В продолжении подсчет равен " + count );

    }

    Console.WriteLine("Продолжение завершено");

  }

  static void Main() {

    Console.WriteLine("Основной поток запущен.");

    // Сконструировать объект первой задачи.

    Task tsk = new Task(MyTask);

    //А теперь создать продолжение задачи.

    Task taskCont = tsk.ContinueWith(ContTask);

    // Начать последовательность задач,

    tsk.Start();

    // Ожидать завершения продолжения.

    taskCont.Wait();

    tsk.Dispose();

    taskCont.Dispose();

    Console.WriteLine("Основной поток завершен.");

  }

}

Ниже приведен результата выполнения данной программы.

Основной поток запущен.

MyTask() запущен

В методе MyTask() подсчет равен 0

В методе MyTask() подсчет равен 1

В методе MyTask() подсчет равен 2

В методе MyTask() подсчет равен 3

В методе MyTask() подсчет равен 4

MyTask завершен

Продолжение запущено

В продолжении подсчет равен 0

В продолжении подсчет равен 1

В продолжении подсчет равен 2

В продолжении подсчет равен 3

В продолжении подсчет равен 4

Продолжение завершено

Основной поток завершен.

Как следует из приведенного выше результата, вторая задача не начинается до тех пор, пока не завершится первая. Обратите также внимание на то, что в методе Main() пришлось ожидать окончания только продолжения задачи. Дело в том, что метод MyTask() как задача завершается еще до начала метода ContTask как продолжения задачи. Следовательно, ожидать завершения метода MyTask() нет никакой надобности, хотя если и организовать такое ожидание, то в этом будет ничего плохого.

Любопытно, что в качестве продолжения задачи нередко применяется лямбда-выражение. Для примера ниже приведен еще один способ организации продолжения задачи из предыдущего примера программы.

//В данном случае в качестве продолжения задачи применяется лямбда-выражение.

Task taskCont = tsk.ContinueWith((first) =>

       {

         Console.WriteLine("Продолжение запущено");

         for(int count = 0; count < 5; count++) {

           Thread.Sleep (500);

           Console.WriteLine("В продолжении подсчет равен " + count );

         }

         Console.WriteLine("Продолжение завершено");

       }

);

В этом фрагменте кода параметр first принимает предыдущую задачу (в данном случае — tsk).

Помимо метода ContinueWith(), в классе Task предоставляются и другие методы, поддерживающие продолжение задачи, обеспечиваемое классом TaskFactory. К их числу относятся различные формы методов ContinueWhenAny() и ContinueWhenAll(), которые продолжают задачу, если завершится любая или все указанные задачи соответственно.

Более 800 000 книг и аудиокниг! 📚

Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением

ПОЛУЧИТЬ ПОДАРОК