Первый вариант намного лучше.
Внутри Parallel.ForEach используется Partitioner<T>
для распределения вашей коллекции по рабочим элементам. Он не будет выполнять одну задачу для каждого элемента, а вместо этого выполнит пакетную обработку, чтобы снизить накладные расходы.
Второй вариант будет планировать один для Task
каждого элемента в вашей коллекции. Хотя результаты будут (почти) одинаковыми, это приведет к гораздо большему количеству служебных данных, чем необходимо, особенно для больших коллекций, и приведет к замедлению общего времени выполнения.
К сведению - используемым Разделителем можно управлять, используя соответствующие перегрузки для Parallel.ForEach , если это необходимо. Для получения дополнительной информации см. Пользовательские разделы на MSDN.
Основным отличием во время выполнения является то, что второе будет работать асинхронно. Это может быть продублировано с помощью Parallel.ForEach, выполнив:
Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));
Делая это, вы по-прежнему пользуетесь секционерами, но не блокируете их до завершения операции.
Я провел небольшой эксперимент по запуску метода «1 000 000 000 (один миллиард)» раз с «Parallel.For» и один с объектами «Задача».
Я измерил время процессора и нашел Parallel более эффективным. Parallel.For разделяет вашу задачу на небольшие рабочие элементы и выполняет их параллельно на всех ядрах оптимальным образом. При создании большого количества объектов задачи (FYI TPL будет использовать внутреннее объединение потоков) будет переносить каждое выполнение каждой задачи, создавая больше напряжения в окне, что видно из эксперимента ниже.
Я также создал небольшое видео, в котором объясняется базовый TPL, а также демонстрируется, как Parallel.For более эффективно использует ваше ядро http://www.youtube.com/watch?v=No7QqSc5cl8 по сравнению с обычными задачами и потоками.
Эксперимент 1
Эксперимент 2
источник
Mehthod1()
в этом примере?Parallel.ForEach оптимизирует (может даже не запускать новые потоки) и блокирует, пока цикл не завершится, а Task.Factory явно создаст новый экземпляр задачи для каждого элемента и возвратит его до завершения (асинхронные задачи). Parallel.Foreach гораздо эффективнее.
источник
На мой взгляд, наиболее реалистичный сценарий - это когда задачи требуют тяжелой работы. Подход Shivprasad фокусируется больше на создании объектов / распределении памяти, чем на самих вычислениях. Я провел исследование, назвав следующий метод:
Выполнение этого метода занимает около 0,5 сек.
Я назвал это 200 раз, используя Parallel:
Тогда я назвал это 200 раз, используя старомодный способ:
Первый случай завершен за 26656мс, второй за 24478мс. Я повторил это много раз. Каждый раз второй подход незначительно быстрее.
источник