Страница 434 из 502
<b> Console.WriteLine("Основной поток запущен.");</b>
<b> // Выполнить параллельно два именованных метода.</b>
<b> Parallel.Invoke(MyMeth, MyMeth2);</b>
<b> Console.WriteLine("Основной поток завершен.");</b>
<b> }</b>
<b>}</b>
Выполнение этой программы может привести к следующему результату.
<b>Основной поток запущен.</b>
<b>MyMeth запущен</b>
<b>MyMeth2 запущен</b>
<b>В методе MyMeth подсчет равен 0</b>
<b>В методе MyMeth2, подсчет равен 0</b>
<b>В методе MyMeth подсчет равен 1</b>
<b>В методе MyMeth2, подсчет равен 1</b>
<b>В методе MyMeth подсчет равен 2</b>
<b>В методе MyMeth2, подсчет равен 2</b>
<b>В методе MyMeth подсчет равен 3</b>
<b>В методе MyMeth2, подсчет равен 3</b>
<b>В методе MyMeth подсчет равен 4</b>
<b>MyMeth завершен</b>
<b>В методе MyMeth2, подсчет равен 4</b>
<b>MyMeth2 завершен</b>
<b>Основной поток завершен.</b>
В данном примере особое внимание обращает на себя следующее обстоятельство: выполнение метода Main() приостанавливается до тех пор, пока не произойдет возврат из метода Invoke(). Следовательно, метод Main(), в отличие от методов MyMeth() и MyMeth2(), не выполняется параллельно. Поэтому применять метод Invoke() показанным здесь способом нельзя в том случае, если требуется, чтобы исполнение вызывающего потока продолжалось.
В приведенном выше примере использовались именованные методы, но для вызова метода Invoke() это условие не является обязательным. Ниже приведен переделанный вариант той же самой программы, где в качестве аргументов в вызове метода Invoke() применяются лямбда-выражения.
<b>// Применить метод Parallel.Invoke() </b>
<b>//для параллельного выполнения двух методов. </b>
<b>// В этой версии программы применяются лямбда-выражения. </b>
<b>using System; </b>
<b>using System.Threading; </b>
<b>using System.Threading.Tasks; </b>
<b>class DemoParallel { </b>
<b> static void Main() { </b>
<b> Console.WriteLine("Основной поток запущен."); </b>
<b> // Выполнить два анонимных метода, указываемых в лямбда-выражениях. </b>
<b> Parallel.Invoke(() => { </b>
<b> Console.WriteLine("Выражение #1 запущено"); </b>
<b> for(int count = 0; count < 5; count++) { </b>
<b> Thread.Sleep(500); </b>
<b> Console.WriteLine("В выражении #1 подсчет равен " + count ); </b>
<b> } </b>
<b> Console.WriteLine("Выражение #1 завершено"); </b>
<b> }, </b>
<b> () => { </b>
<b> Console.WriteLine("Выражение #2 запущено"); </b>
<b> for (int count = 0; count < 5; count++) { </b>
<b> Thread.Sleep(500); </b>
<b> Console.WriteLine("В выражении #2 подсчет равен " + count ); </b>
<b> } </b>
<b> Console.WriteLine("Выражение #1 завершено"); </b>
<b> } );</b>
<b> Console.WriteLine("Основной поток завершен."); </b>
<b> } </b>
<b>} </b>
Эта программа дает результат, похожий на результат выполнения предыдущей программы.
В TPL параллелизм данных поддерживается, в частности, с помощью метода For(), определенного в классе Parallel. Этот метод существует в нескольких формах. Его рассмотрение мы начнем с самой простой формы, приведенной ниже:
<b>public static ParallelLoopResult</b>
<b> For(int fromlnclusive, int toExclusive, Action<int> body)</b>
где fromlnclusive обозначает начальное значение того, что соответствует переменной управления циклом; оно называется также итерационным, или индексным, значением; a toExclusive — значение, на единицу больше конечного. На каждом шаге цикла переменная управления циклом увеличивается на единицу. Следовательно, цикл постепенно продвигается от начального значения fromlnclusive к конечному значению toExclusive минус единица. Циклически выполняемый код указывается методом, передаваемым через параметр body. Этот метод должен быть совместим с делегатом Action<int>, объявляемым следующим образом.