Параллельный .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
});