Цикл Parallel.For использует ThreadPool для выполнения работы в цикле, вызывая делегат один раз за каждую итерацию цикла.
Общая идея работы Parallel.For может быть представлена следующим образом:
public static void MyParallelFor(int inclusiveLowerBound, int exclusiveUpperBound, Action<int> body)
{
// Get the number of processors, initialize the number of remaining
// threads, and set the starting point for the iteration.
int numProcs = Environment.ProcessorCount;
int remainingWorkItems = numProcs;
int nextIteration = inclusiveLowerBound;
using (ManualResetEvent mre = new ManualResetEvent(false))
{
// Create each of the work items.
for (int p = 0; p < numProcs; p++)
{
ThreadPool.QueueUserWorkItem(delegate
{
int index;
while ((index = Interlocked.Increment(ref nextIteration) - 1) < exclusiveUpperBound)
body(index);
if (Interlocked.Decrement(ref remainingWorkItems) == 0)
mre.Set();
});
}
// Wait for all threads to complete.
mre.WaitOne();
}
}
Parallel.For возвращает тип значения ParallelLoopResult, который содержит сведения о завершенном цикле.Одна из его перегрузок выглядит следующим образом:
public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);
Важно понимать, что параллельное выполнение не всегда быстрее, чем последовательное выполнение.Чтобы решить, использовать ли параллель или нет, вы должны оценить рабочую нагрузку, которая будет выполняться на итерацию цикла.Если фактическая работа, выполняемая циклом, мала по сравнению со стоимостью синхронизации потока, лучше использовать обычный цикл.
Это один из примеров, когда последовательный цикл для производительности быстрее параллельного:
static void Main(string[] args)
{
Action<int> action = new Action<int>(SimpleMethod);
// ordinary For loop performance estimation
var sw = Stopwatch.StartNew();
for(int i = 0; i < 1000; i++)
action(i);
Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);
// parallel For loop performance estimation
sw = Stopwatch.StartNew();
Parallel.For(0, 1000, action);
Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);
}
static void SimpleMethod(int index)
{
int d = 1;
int result = index / d;
}
Выход:
0.0001963 sec.
0.0346729 sec.