Распараллеливание задач методом Invoke()



 

Метод Invoke(), определенный в классе Parallel, позволяет выполнять один или несколько методов, указываемых в виде его аргументов. Он также масштабирует исполнение кода, используя доступные процессоры, если имеется такая возможность. Ниже приведена простейшая форма его объявления.

 

public static void Invoke(params Action[] actions)

 

Выполняемые методы должны быть совместимы с описанным ранее делегатом Action. Напомним, что делегат Action объявляется следующим образом.

 

Public delegate void Action()

 

Следовательно, каждый метод, передаваемый методу Invoke() в качестве аргумента, не должен ни принимать параметров, ни возвращать значение. Благодаря тому что параметр actions данного метода относится к типу params, выполняемые методы могут быть указаны в виде переменного списка аргументов. Для этой цели можно также воспользоваться массивом объектов типа Action, но зачастую оказывается проще указать список аргументов.

Метод Invoke() сначала инициирует выполнение, а затем ожидает завершения всех передаваемых ему методов. Это, в частности, избавляет от необходимости (да и не позволяет) вызывать метод Wait(). Все функции параллельного выполнения метод Wait() берет на себя. И хотя это не гарантирует, что методы будут действительно выполняться параллельно, тем не менее, именно такое их выполнение предполагается, если система поддерживает несколько процессоров. Кроме того, отсутствует возможность указать порядок выполнения методов от первого и до последнего, и этот порядок не может быть таким же, как и в списке аргументов.

В приведенном ниже примере программы демонстрируется применение метода Invoke() на практике. В этой программе два метода MyMeth() и MyMeth2() выполняются параллельно посредством вызова метода Invoke(). Обратите внимание на простоту организации данного процесса.

 

// Применить метод Parallel.Invoke() для параллельного выполнения двух методов.

using System;

using System.Threading;

using System.Threading.Tasks;

class DemoParallel {

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

static void MyMeth() {

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

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

Thread.Sleep(500);

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

}

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

}

 

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

static void MyMeth2() {

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

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

Thread.Sleep(500);

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

}

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

}

 

static void Main() {

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

Выполнить параллельно два именованных метода.

Parallel.Invoke(MyMeth, MyMeth2);

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

}

}

 

Выполнение этой программы может привести к следующему результату.

 

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

MyMeth запущен

MyMeth2 запущен

В методе MyMeth подсчет равен 0

В методе MyMeth2, подсчет равен 0

В методе MyMeth подсчет равен 1

В методе MyMeth2, подсчет равен 1

В методе MyMeth подсчет равен 2

В методе MyMeth2, подсчет равен 2

В методе MyMeth подсчет равен 3

В методе MyMeth2, подсчет равен 3

В методе MyMeth подсчет равен 4

MyMeth завершен

В методе MyMeth2, подсчет равен 4

MyMeth2 завершен

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

 

В данном примере особое внимание обращает на себя следующее обстоятельство: выполнение метода Main() приостанавливается до тех пор, пока не произойдет возврат из метода Invoke(). Следовательно, метод Main(), в отличие от методов MyMeth() и MyMeth2(), не выполняется параллельно. Поэтому применять метод Invoke() показанным здесь способом нельзя в том случае, если требуется, чтобы исполнение вызывающего потока продолжалось.

В приведенном выше примере использовались именованные методы, но для вызова метода Invoke() это условие не является обязательным. Ниже приведен переделанный вариант той же самой программы, где в качестве аргументов в вызове метода Invoke() применяются лямбда-выражения.

 

// Применить метод Parallel.Invoke()  

//для параллельного выполнения двух методов.  

// В этой версии программы применяются лямбда-выражения.  

using System;  

using System.Threading;  

using System.Threading.Tasks;  

 

class DemoParallel {  

static void Main() {  

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

 

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

Parallel.Invoke(() => {  

Console.WriteLine("Выражение #1 запущено");  

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

Thread.Sleep(500);  

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

}  

Console.WriteLine("Выражение #1 завершено");  

},  

() => {  

Console.WriteLine("Выражение #2 запущено");  

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

Thread.Sleep(500);  

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

}  

Console.WriteLine("Выражение #1 завершено");  

} );

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

}  

}  

 

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

 

 

Применение метода For()

 

В TPL параллелизм данных поддерживается, в частности, с помощью метода For(), определенного в классе Parallel. Этот метод существует в нескольких формах. Его рассмотрение мы начнем с самой простой формы, приведенной ниже:

 


Дата добавления: 2019-02-12; просмотров: 331; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!