Parallel.ForEach () a foreach (IEnumerable <T> .AsParallel ())

143

Erg, próbuję znaleźć te dwie metody w BCL przy użyciu reflektora, ale nie mogę ich zlokalizować. Jaka jest różnica między tymi dwoma fragmentami?

ZA:

IEnumerable<string> items = ...

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

B:

IEnumerable<string> items = ...

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

Czy istnieją różne konsekwencje używania jednego względem drugiego? (Załóżmy, że wszystko, co robię w nawiasach kwadratowych obu przykładów, jest bezpieczne dla wątków).

SnickersAreMyFave
źródło

Odpowiedzi:

148

Robią coś zupełnie innego.

Pierwsza przyjmuje anonimowego delegata i uruchamia wiele wątków w tym kodzie równolegle dla wszystkich różnych elementów.

Drugi niezbyt przydatny w tym scenariuszu. Krótko mówiąc, ma na celu wykonanie zapytania w wielu wątkach, połączenie wyniku i ponowne przekazanie go do wątku wywołującego. Zatem kod w instrukcji foreach pozostaje zawsze w wątku interfejsu użytkownika.

Ma to sens tylko wtedy, gdy wykonasz coś kosztownego w zapytaniu linq po prawej stronie AsParallel()wywołania, na przykład:

 var fibonacciNumbers = numbers.AsParallel().Select(n => ComputeFibonacci(n));
svick
źródło
Jaka jest korzyść z prostego wykonywania równoległego foreach na computefibonacci?
l --''''''--------- '' '' '' '' '' ''
51

Różnica polega na tym, że B nie jest równoległe. Jedyną rzeczą AsParallel()jest to, że zawija się wokół a IEnumerable, więc gdy używasz metod LINQ, używane są ich równoległe warianty. Opakowanie GetEnumerator()(które jest używane za kulisami w foreach) zwraca nawet wynik oryginalnej kolekcji GetEnumerator().

BTW, jeśli chcesz spojrzeć na metody w Reflector, AsParallel()znajduje się w System.Linq.ParallelEnumerableklasie w System.Corezestawie. Parallel.ForEach()znajduje się w mscorlibzestawie (przestrzeni nazw System.Threading.Tasks).

svick
źródło
Co masz na myśli, mówiąc ... Ich równoległe warianty są używane ...?
l --''''''--------- '' '' '' '' '' ''
2
@punctuation To, na przykład, kiedy piszesz .Select(), wywołuje, ParallelEnumerable.Select()a nie normalne Enumerable.Select().
svick
50

Druga metoda nie będzie równoległa do prawidłowego sposobu użycia AsParallel () w twoim przykładzie

IEnumerable<string> items = ...

items.AsParallel().ForAll(item =>
{
    //Do parallel stuff here
});
Scott Chamberlain
źródło
3
Po co używać kombinacji asparallel wraz z forall zamiast po prostu foreach?
l --''''''--------- '' '' '' '' '' ''