Как следует из приведенного выше результата, выполнение метода MyTask()
Main()
лишь две секунды спустя. Следовательно, в методе MyTask()
выполняются четыре шага цикла. Когда же перехватывается исключение AggregateException
, проверяется состояние задачи. Если задача tsk
отменена, что и должно произойти в данном примере, то об этом выводится соответствующее сообщение. Следует, однако, иметь в виду, что когда сообщение AggregateException
генерируется в ответ на отмену задачи, то это еще не свидетельствует об ошибке, а просто означает, что задача была отменена.Выше были изложены лишь самые основные принципы, положенные в основу отмены задачи и генерирования исключения AggregateException
Другие средства организации задач
В предыдущих разделах был описан ряд понятий и основных способов организации и исполнения задач. Но имеются и другие полезные средства. В частности, задачи можно делать вложенными, когда одни задачи способны создавать другие, или же порожденными, когда вложенные задачи оказываются тесно связанными с создающей их задачей.
В предыдущем разделе было дано краткое описание исключения AggregateException
Flatten()
, применяемый для преобразования любых внутренних исключений типа AggregateException
в единственное исключение AggregateException
. Другой метод, Handle()
, служит для обработки исключения, составляющего совокупное исключение AggregateException
.При создании задачи имеется возможность указать различные дополнительные параметры, оказывающие влияние на особенности ее исполнения. Для этой цели указывается экземпляр объекта типа TaskCreationOptions
Task
или же в фабричном методе StartNew()
. Кроме того, в классе TaskFactory
доступно целое семейство методов FromAsync()
, поддерживающих модель асинхронного программирования (АРМ — Asynchronous Programming Model).Как упоминалось ранее в этой главе, задачи планируются на исполнение экземпляром объекта класса TaskScheduler
Класс Parallel
В примерах, приведенных до сих пор в этой главе, демонстрировались ситуации, в которых библиотека TPL использовалась таким же образом, как и класс Thread
Parallel
, который упрощает параллельное исполнение кода и предоставляет методы, рационализирующие оба вида параллелизма: данных и задач.Класс Parallel
For(), For Each()
и Invoke()
. У каждого из этих методов имеются различные формы. В частности, метод For()
выполняет распараллеливаемый цикл for
, а метод ForEach()
— распараллеливаемый цикл foreach
, и оба метода поддерживают параллелизм данных. А метод Invoke()
поддерживает параллельное выполнение двух методов или больше. Как станет ясно дальше, эти методы дают преимущество реализации на практике распространенных методик параллельного программирования, не прибегая к управлению задачами или потоками явным образом. В последующих разделах каждый из этих методов будет рассмотрен более подробно.Метод Invoke()
Parallel
, позволяет выполнять один или несколько методов, указываемых в виде его аргументов. Он также масштабирует исполнение кода, используя доступные процессоры, если имеется такая возможность. Ниже приведена простейшая форма его объявления.public static void Invoke(params Action[] actions)
Выполняемые методы должны быть совместимы с описанным ранее делегатом Action
Action
объявляется следующим образом.public delegate void Action()
Следовательно, каждый метод, передаваемый методу Invoke()
params
, выполняемые методы могут быть указаны в виде переменного списка аргументов. Для этой цели можно также воспользоваться массивом объектов типа Action
, но зачастую оказывается проще указать список аргументов.