Различия между Parallel.ForEach и await ForEachAsync - PullRequest
0 голосов
/ 27 марта 2019

Есть ли причина выбирать Parallel.ForEach вместо await ForEachAsync в любой ситуации (или наоборот)? или они практически одинаковые?

await collection.ForEachAsync( m => { m.DoSomething(); } );

VS

Parallel.ForEach( collection, m => { m.DoSomething(); } );

Ответы [ 3 ]

2 голосов
/ 27 марта 2019

Они вовсе не "практически одинаковы".

Когда вы используете функции из класса Parallel , такие как Parallel.ForEach(), вы вызываете какое-то действие, в котором это действие разбивается на несколько меньших действий, каждое из которых выполняется в разных потоках (иначе говоря, резьбовое).

ForEachAsync, с другой стороны, не обязательно многопоточный. Это асинхронные и асинхронные операции не являются многопоточными (ну, они могут быть, но не обязательно, это зависит от реализации).

Я настоятельно рекомендую прочитать следующую запись , в которой более подробно рассматривается эта тема.

Что касается вас, вопрос

Есть ли причина выбирать Parallel.ForEach вместо ожидающего ForEachAsync в любой ситуации

Ответ наиболее определенно состоит в том, что для этого есть причины, но для того, чтобы определить, какие сценарии вы бы использовали, один или другой, вам необходимо понять их оба.

Вот простой пример:

У вас есть коллекция объектов, и вы хотите перебрать их и выполнить какое-то действие. Вы заботитесь о порядке, в котором эти действия происходят? Если это так, не используйте Parallel.ForEach(), так как нет гарантии порядка, в котором они вызываются (из-за его многопоточности).

EDIT:

В вашем примере все зависит от количества элементов в collection и степени загруженности DoSomething().

Причина этого в том, что Parallel.ForEach() является несвободным . Есть компромиссы, которые нужно сделать. Настройка многопоточной среды занимает время, и если collection мало и / или DoSomething() не занимает слишком долго, то время, потраченное на настройку этих потоков, будет лучше (и обычно быстрее ) проведено с помощью однопоточной асинхронной операции.

С другой стороны, если collection велико и / или DoSomething() является трудоемкой задачей, тогда Parallel.ForEach(), безусловно, будет наиболее эффективным вариантом.

0 голосов
/ 01 апреля 2019

Есть ли причина выбирать Parallel.ForEach вместо await ForEachAsync в любой ситуации (или наоборот)?

Parallel.ForEach для синхронного кода.Его делегат должен быть синхронным, и он вызывается синхронно.

ForEachAsync не является стандартным алгоритмом.Существует несколько различных реализаций, но обычно они пытаются смешать асинхронность и параллелизм.Они должны отказаться от некоторых аспектов самобалансирующейся Parallel.ForEach.Подавляющее большинство кода не нуждается в ForEachAsync;большинство кодов асинхронный или параллельный.

0 голосов
/ 28 марта 2019

все зависит от потоков, скажем, у вас есть следующий класс

public class person
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

и вот ваш основной класс

List<person> persons = new List<person>()
            {
                new person{ ID = 1,Name="Ali"}
                ,new person{ ID = 2,Name="Gorge"}
                ,new person{ ID = 3,Name="Alex"}
                ,new person{ ID = 4,Name="Liz"}
                ,new person{ ID = 5,Name="Scott"}
                ,new person{ ID = 6,Name="Abby"}
                ,new person{ ID = 7,Name="Sarah"}
            };

            Parallel.ForEach(persons, (p) =>
            {
                Console.WriteLine($"Id : {p.ID} ,Name : {p.Name}");
            });

Когда вы запустите этот код, элементы списка будутбыть разделен на потоки diff, и код не будет работать по порядку, как вы видите в следующем выводе, я получаю печать в порядке diff, чем мой оригинальный список enter image description here

и здесьЯ запускаю тот же код еще раз, но я получаю результаты сравнения

enter image description here

Причина в том, что из-за потоков компилятор делится на числопотоков и каждый список запускает элементы, назначенные ему на следующем рисунке показаны различия потоков

enter image description here

, но при запуске следующий код

List<person> persons = new List<person>()
            {
                new person{ ID = 1,Name="Ali"}
                ,new person{ ID = 2,Name="Gorge"}
                ,new person{ ID = 3,Name="Alex"}
                ,new person{ ID = 4,Name="Liz"}
                ,new person{ ID = 5,Name="Scott"}
                ,new person{ ID = 6,Name="Abby"}
                ,new person{ ID = 7,Name="Sarah"}
            };

            await persons.ForEachAsync(async p => Console.WriteLine($"Id : {p.ID} ,Name : {p.Name}"));

вы получаете только одну нить, как показано здесь

enter image description here

плюс печать данных всегда будет выполняться в том же порядке из вашего списка

Надеюсь, этот ответ объясняет разницу!

...