Вопрос по c#, multithreading, .net – C # - Parallel.Invoke и Parallel.ForEach по сути одно и то же?

16

И "тем же самым" Я имею в виду, выполняют ли эти две операции одну и ту же работу, и все сводится к тому, какую из них более удобно вызывать, исходя из того, с чем вам приходится работать? (т. е. список делегатов или список вещей для повторения)? Я искал в MSDN, StackOverflow и в различных случайных статьях, но пока не нашел четкого ответа на этот вопрос.

EDIT: I should have been clearer; I am asking if the two methods do the same thing because if they do not, I would like to understand which would be more efficient.

Пример: у меня есть список из 500 ключевых значений. В настоящее время я использую цикл foreach, который перебирает список (последовательно) и выполняет работу для каждого элемента. Если я хочу использовать преимущества нескольких ядер, должен ли я вместо этого просто использовать Parallel.ForEach? скажем, ради аргументов, что у меня был массив из 500 делегатов для этих 500 задач - будет ли чистый эффект вызова Parallel.Invoke и выдачи ему списка из 500 делегатов?

Спасибо заранее!

Ваш Ответ

3   ответа
23

Parallel.ForEach проходит через список элементов и может выполнять некоторые задачи над элементами массива.

например.

Parallel.ForEach(val, (array) => Sum(array));

Parallel.Invoke может вызывать много функций параллельно.

например.

Parallel.Invoke(
() => doSum(array),
() => doAvg(array),
() => doMedian(array));

Как и в приведенном выше примере, вы можете видеть, что они отличаются по функциональности.ForEach перебираетList элементов и выполняетone task наeach element параллельно, в то время какInvoke может выполнятьmany tasks параллельно наsingle element.

& quot; Parallel.ForEach ... может выполнять некоторые задачи над элементами массива. & quot; Так что, если моя задача - вызвать функцию? Есть ли реальная разница в сравнении с Parallel.Invoke с точки зрения того, как работа выполняется, и превзойдет ли одна другую другую? Brad Gagne
1. Parallel.ForEach(val, (array) => Sum(array)); вызывает функциюSum()так что да, он может вызывать функцию. 2. Я думаю, это зависит только от того, что вам нужно сделать. Если вы вызываете одну функцию в списке элементов, чемParallel.ForEach кажется хорошим выбором, но если вы вызываете более одной функции наList элементов или одного элемента, чемParallel.Invoke будет работать лучше всего.
0

Причина в том, что Invoke работает над массивом действий, а ForEach работает со списком (в частности, IEnumerable) действий; Списки значительно отличаются от массивов в механике, хотя они демонстрируют тот же тип базового поведения.

Я не могу сказатьwhat Разница на самом деле влечет за собой, потому что я не знаю, поэтому, пожалуйста, не принимайте это как ответ (если вы действительно этого не хотите!), но я надеюсь, что это пробудит у кого-то память о механизмах.

+1 за хороший вопрос тоже.

Редактировать; Мне просто пришло в голову, что есть и другой ответ; Invoke может работать с динамическим списком действий; но Foreach может работать с универсальным IEnumerable из Actions и дает вам возможность использовать условную логику Action by Action; так что вы можете проверить условие перед произнесением Action.Invoke () в каждой итерации Foreach.

В таком случае; нет, они не являются ". ForEach предоставляет вам доступ к действию до его вызова; Invoke просто делает это.
Спасибо за ответ, Расс. Я понимаю разницу с точки зрения сигнатур методов, мне просто интересно, используют ли они оба одинаковый подход для пережевывания работы. Brad Gagne
9

ния действий) функционируют одинаково, хотя да, в частности, требуется, чтобы коллекция была массивом. Рассмотрим следующий пример:

List<Action> actionsList = new List<Action>
            {
                () => Console.WriteLine("0"),
                () => Console.WriteLine("1"),
                () => Console.WriteLine("2"),
                () => Console.WriteLine("3"),
                () => Console.WriteLine("4"),
                () => Console.WriteLine("5"),
                () => Console.WriteLine("6"),
                () => Console.WriteLine("7"),
                () => Console.WriteLine("8"),
                () => Console.WriteLine("9"),
            };

            Parallel.ForEach<Action>(actionsList, ( o => o() ));

            Console.WriteLine();

            Action[] actionsArray = new Action[]
            {
                () => Console.WriteLine("0"),
                () => Console.WriteLine("1"),
                () => Console.WriteLine("2"),
                () => Console.WriteLine("3"),
                () => Console.WriteLine("4"),
                () => Console.WriteLine("5"),
                () => Console.WriteLine("6"),
                () => Console.WriteLine("7"),
                () => Console.WriteLine("8"),
                () => Console.WriteLine("9"),
            };

            Parallel.Invoke(actionsArray);

            Console.ReadKey();

Этот код производит этот вывод за один прогон. Выходные данные, как правило, каждый раз находятся в другом порядке.

0 5 1 6 2 7 3 8 4 9

0 1 2 4 5 6 7 8 9 3

По моему опыту, они ведут себя одинаково. Это может потребовать больше усилий, чем вы хотите, но если вы загрузите последнюю версию .NET Reflector и откроете mscorlib.dll, вы сможете увидеть точный ответ на ваш вопрос, заглянув в класс Parallel в System.Threading.Tasks. Это то, что я хотел бы сделать.
Спасибо, плукич. В моем конкретном случае у меня есть некоторые «огонь и забыл» выполняемая работа, поэтому меня не интересуют возвращаемые значения или даже порядок их выполнения. Поэтому мне было просто любопытно, была ли какая-либо разница / польза в вызове того или другого. Brad Gagne

Похожие вопросы