Параллельный .ForEach() против foreach (IEnumerable <T>.AsParallel())

Эрг, я пытаюсь найти эти два метода в BCL с помощью Reflector, но не могу их найти. Какая разница между этими двумя фрагментами?

А:

IEnumerable<string> items = ...

Parallel.ForEach(items, item => {
   ...
});

В:

IEnumerable<string> items = ...

foreach (var item in items.AsParallel())
{
   ...
}

Существуют ли разные последствия использования одного над другим? (Предположим, что все, что я делаю в скобках в обоих примерах, является потокобезопасным.)

Ответ 1

Они делают что-то совсем другое.

Первый принимает анонимный делегат и выполняет несколько потоков для этого кода параллельно для всех разных элементов.

Второй не очень полезен в этом сценарии. В двух словах она предназначена для выполнения запроса по нескольким потокам и объединения результата, а затем возвращает его вызывающему потоку. Таким образом, код инструкции foreach всегда остается в потоке пользовательского интерфейса.

Это имеет смысл, если вы делаете что-то дорогое в запросе linq справа от вызова AsParallel(), например:

 var fibonacciNumbers = numbers.AsParallel().Select(n => ComputeFibonacci(n));

Ответ 2

Разница в том, что B не параллелен. Единственное, что делает AsParallel(), это то, что он обтекает IEnumerable, поэтому при использовании методов LINQ используются их параллельные варианты. Обертка GetEnumerator() (которая используется за кулисами в foreach) даже возвращает результат исходной коллекции GetEnumerator().

Кстати, если вы хотите посмотреть методы в Reflector, AsParallel() находится в классе System.Linq.ParallelEnumerable в сборке System.Core. Parallel.ForEach() находится в сборке mscorlib (пространство имен System.Threading.Tasks).

Ответ 3

Второй метод не будет параллельным правильным способом использования AsParallel() в вашем примере будет

IEnumerable<string> items = ...

items.AsParallel().ForAll(item =>
{
    //Do parallel stuff here
});