Методы Parallel.For()
и Parallel.ForEach()
используют Partitioner. Было бы очень неэффективно выполнять цикл из 10 000 элементов на 10 000 отдельных задач. Разделитель разбивает данные на сегменты, и в идеале ForEach()
будет выполняться в 4 Задачи (потоки) из 2500 элементов на 4-ядерном процессоре. Иногда это требует некоторой эвристики, и вы можете написать свой собственный разделитель.
При использовании «обычных» (простых) перегрузок ForEach()
это полностью прозрачно. Но в вашем примере используется одна из перегрузок <TLocal>
, которая покрывает разделение.
Оператор subtotal += nums[j];
повторяется внутри 1 раздела и поэтому является потокобезопасным.
И (finalResult) => Interlocked.Add(ref total,finalResult)
, где разделы объединяются, эта часть, конечно, не является поточно-ориентированной.