Страница 423 из 502
Создать новую задачу в виде объекта класса Task и начать ее исполнение можно самыми разными способами. Для начала создадим объект типа Task с помощью конструктора и запустим его, вызвав метод Start(). Для этой цели в классе Task определено несколько конструкторов. Ниже приведен тот конструктор, которым мы собираемся воспользоваться:
<b>public Task(Action действие)</b>
где действие обозначает точку входа в код, представляющий задачу, тогда как Action — делегат, определенный в пространстве имен System. Форма делегата Action, которой мы собираемся воспользоваться, выглядит следующим образом.
<b>public delegate void Action()</b>
Таким образом, точкой входа должен служить метод, не принимающий никаких параметров и не возвращающий никаких значений. (Как будет показано далее, делегату Action можно также передать аргумент.)
Как только задача будет создана, ее можно запустить на исполнение, вызвав метод Start(). Ниже приведена одна из его форм.
<b>public void Start()</b>
После вызова метода Start() планировщик задач запланирует исполнение задачи. В приведенной ниже программе все изложенное выше демонстрируется на практике. В этой программе отдельная задача создается на основе метода MyTask(). После того как начнет выполняться метод Main(), задача фактически создается и запускается на исполнение. Оба метода MyTask() и Main() выполняются параллельно.
<b>// Создать и запустить задачу на исполнение.</b>
<b>using System;</b>
<b>using System.Threading;</b>
<b>using System.Threading.Tasks;</b>
<b>class DemoTask {</b>
<b> static void MyTask() {</b>
<b> Console.WriteLine("MyTask() запущен");</b>
<b> for(int count = 0; count < 10; count++) {</b>
<b> Thread.Sleep(500);</b>
<b> Console.WriteLine("В методе MyTask(), подсчет равен " + count);</b>
<b> }</b>
<b> Console.WriteLine("MyTask завершен");</b>
<b> }</b>
<b> static void Main() {</b>
<b> Console.WriteLine("Основной поток запущен.");</b>
<b> // Сконструировать объект задачи.</b>
<b> Task tsk = new Task(MyTask);</b>
<b> // Запустить задачу на исполнение,</b>
<b> tsk.Start();</b>
<b> // метод Main() активным до завершения метода MyTask().</b>
<b> for(int i = 0; i < 60; i++) {</b>
<b> Console.Write(".");</b>
<b> Thread.Sleep(100);</b>
<b> }</b>
<b> Console.WriteLine("Основной поток завершен.");</b>
<b> }</b>
<b>}</b>
Ниже приведен результат выполнения этой программы. (У вас он может несколько отличаться в зависимости от загрузки задач, операционной системы и прочих факторов.)
<b>Основной поток запущен.</b>
<b>.MyTask() запущен</b>
<b>....В методе MyTask(), подсчет равен 0</b>
<b>.....В методе MyTask(), подсчет равен 1</b>
<b>.....В методе MyTask(), подсчет равен 2</b>
<b>....В методе MyTask(), подсчет равен 3</b>
<b>.....В методе MyTask(), подсчет равен 4</b>
<b>.....В методе MyTask(), подсчет равен 5</b>
<b>....В методе MyTask(), подсчет равен 6</b>
<b>.....В методе MyTask(), подсчет равен 7</b>
<b>.....В методе MyTask(), подсчет равен 8</b>
<b>.....В методе MyTask(), подсчет равен 9</b>
<b>MyTask завершен</b>
<b>............Основной поток завершен.</b>
Следует иметь в виду, что по умолчанию задача исполняется в фоновом потоке. Следовательно, при завершении создающего потока завершается и сама задача. Именно поэтому в рассматриваемой здесь программе метод Thread.Sleep() использован для сохранения активным основного потока до тех пор, пока не завершится выполнение метода MyTask(). Как и следовало ожидать, организовать ожидание завершения задачи можно и более совершенными способами, что и будет показано далее.
В приведенном выше примере программы задача, предназначавшаяся для параллельного исполнения, обозначалась в виде статического метода. Но такое требование к задаче не является обязательным. Например, в приведенной ниже программе, которая является переработанным вариантом предыдущей, метод MyTask(), выполняющий роль задачи, инкапсулирован внутри класса.
<b>// Использовать метод экземпляра в качестве задачи.</b>