Równolegle.ForEach vs Task.Uruchom i zadanie.WhenAll

Jakie są różnice między używaniem Parallel.ForEach lub zadanie.Run() aby uruchomić zestaw zadań asynchronicznie?

Wersja 1:

List<string> strings = new List<string> { "s1", "s2", "s3" };
Parallel.ForEach(strings, s =>
{
    DoSomething(s);
});

Wersja 2:

List<string> strings = new List<string> { "s1", "s2", "s3" };
List<Task> Tasks = new List<Task>();
foreach (var s in strings)
{
    Tasks.Add(Task.Run(() => DoSomething(s)));
}
await Task.WhenAll(Tasks);
Author: Petter T, 2013-10-01

3 answers

W tym przypadku druga metoda będzie asynchronicznie czekać na zakończenie zadań zamiast blokowania.

Istnieje jednak wada użycia Task.Run W PĘTLI - Z Parallel.ForEach, Istnieje Partitioner który zostaje stworzony, aby uniknąć wykonywania większej liczby zadań niż jest to konieczne. Task.Run zawsze tworzy jedno zadanie na element (ponieważ to robisz), ale partie klas Parallel działają, więc tworzysz mniej zadań niż wszystkie elementy robocze. Może to zapewnić znacznie lepszą ogólną wydajność, zwłaszcza, jeśli korpus pętli ma niewielką ilość pracy na przedmiot.

Jeśli tak jest, możesz połączyć obie opcje pisząc:

await Task.Run(() => Parallel.ForEach(strings, s =>
{
    DoSomething(s);
}));

Zauważ, że można to również zapisać w tej krótszej formie:

await Task.Run(() => Parallel.ForEach(strings, DoSomething));
 110
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-30 20:33:52

Pierwsza wersja synchronicznie zablokuje wywołujący wątek (i uruchomi na nim niektóre zadania).
Jeśli jest to wątek interfejsu, spowoduje to zamrożenie interfejsu.

Druga wersja uruchomi zadania asynchronicznie w puli wątków i zwolni wywołujący wątek, dopóki nie zostaną wykonane.

Istnieją również różnice w algorytmach szeregowania.

Zauważ, że twój drugi przykład może zostać skrócony do

await Task.WhenAll(strings.Select(s => Task.Run(() => DoSomething(s)));
 28
Author: SLaks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-30 20:15:05

Skończyło się na tym, że łatwiej było to przeczytać:

  List<Task> x = new List<Task>();
  foreach(var s in myCollectionOfObject)
  {
      // Note there is no await here. Just collection the Tasks
      x.Add(s.DoSomethingAsync());
  }
  await Task.WhenAll(x);
 0
Author: Chris M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-14 02:21:21