if(data[i] > 20000 & data[i] < 30000) data[i] = 200;
if(data[i] > 30000) data[i] = 300;
}
static void Main() {
Console.WriteLine("Основной поток запущен.");
data = new int[100000000];
// Инициализировать данные в обычном цикле for.
for (int i=0; i < data.Length; i++) data[i] = i;
// Распараллелить цикл методом For().
Parallel.For(0, data.Length, MyTransform);
Console.WriteLine("Основной поток завершен.");
}
}
Эта программа состоит из двух циклов. В первом, стандартном, цикле for инициализируется массив data
. А во втором цикле, выполняемом параллельно методом For()
, над каждым элементом массива data
производится преобразование. Как упоминалось выше, это преобразование носит произвольный характер и выбрано лишь для целей демонстрации. Метод For()
автоматически разбивает вызовы метода MyTransform()
на части для параллельной обработки отдельных порций данных, хранящихся в массиве. Следовательно, если запустить данную программу на компьютере с двумя доступными процессорами или больше, то цикл преобразования данных в массиве может быть выполнен методом For()
параллельно.
Следует, однако, иметь в виду, что далеко не все циклы могут выполняться эффективно, когда они распараллеливаются. Как правило, мелкие циклы, а также циклы, состоящие из очень простых операций, выполняются быстрее последовательным способом, чем параллельным. Именно поэтому цикл for
инициализации массива данных не распараллеливается методом For()
в рассматриваемой здесь программе. Распараллеливание мелких и очень простых циклов может оказаться неэффективным потому, что время, требующееся для организации параллельных задач, а также время, расходуемое на переключение контекста, превышает время, экономящееся благодаря параллелизму. В подтверждение этого факта в приведеннрм ниже примере программы создаются последовательный и параллельный варианты цикла for
, а для сравнения на экран выводится время выполнения каждого из них.
// Продемонстрировать отличия во времени последовательного
//и параллельного выполнения цикла for.
using System;
using System.Threading.Tasks;
using System.Diagnostics;
class DemoParallelFor {
static int[] data;
// Метод, служащий в качестве тела параллельно выполняемого цикла.
// Операторы этого цикла просто расходуют время ЦП для целей демонстрации,
static void MyTransform(int i) {
data[i] = data[i] / 10;
if(data[i] < 1000) data[i] = 0;
if(data[i] > 1000 & data[i] < 2000) data[i] = 100;
if(data[i] > 2000 & data[i] < 3000) data[i] = 200;
if(data[i] > 3000) data[i] = 300;
}
static void Main() {
Console.WriteLine("Основной поток запущен.");
// Create экземпляр объекта типа Stopwatch
// для хранения времени выполнения цикла.
Stopwatch sw = new Stopwatch();
data = new int[100000000];
// Инициализировать данные,
sw.Start();
// Параллельный вариант инициализации массива в цикле.
Parallel.For(0, data.Length, (i) => data[i] = i );
sw.Stop();
Console.WriteLine("Параллельно выполняемый цикл инициализации: " +
"{0} секунд", sw.Elapsed.TotalSeconds);
sw.Reset();
sw.Start();
// Последовательный вариант инициализации массива в цикле,
for(int i=0; i < data.Length; i++) data[i] = i;
sw.Stop();
Console.WriteLine("Последовательно выполняемый цикл инициализации: " +
"{0} секунд", sw.Elapsed.TotalSeconds);
Console.WriteLine();
// Выполнить преобразования,
sw.Start();