Когда использовать Parallel.For? - PullRequest
       7

Когда использовать Parallel.For?

7 голосов
/ 15 сентября 2010

Я недавно перешел на C # .net 4.

Я люблю Parallel.For, но не уверен, когда использовать, а когда нет.Я знаю, что когда заказ не важен для меня - я буду его использовать.

Но есть ли какие-либо тесты, касающиеся накладных расходов при работе с Parallels?Это означает, что если мой цикл выполняется только 10 раз (и выполняет очень мало логики) - мне следует избегать Parallels?Есть ли какие-нибудь правила для большого пальца?

Ответы [ 3 ]

4 голосов
/ 15 сентября 2010

Я бы не стал использовать Parallel.For, если производительность не является проблемой.

Написание кода, который выполняется одновременно, обычно сложнее, чем написание однопоточного кода.Кроме того, если вы делаете ошибку из-за проблемы параллелизма, может быть трудно отладить ее.Например, ошибка может возникать только иногда и не может быть легко воспроизведена.Если у вас нет особой необходимости в повышении производительности, я бы посоветовал вам сохранить ее простоту и использовать обычный цикл в одном потоке.

1 голос
/ 03 июля 2017

Цикл Parallel.For использует ThreadPool для выполнения работы в цикле, вызывая делегат один раз за каждую итерацию цикла.

Общая идея работы Parallel.For может быть представлена ​​следующим образом:

public static void MyParallelFor(int inclusiveLowerBound, int exclusiveUpperBound, Action<int> body)
{
    // Get the number of processors, initialize the number of remaining
    // threads, and set the starting point for the iteration.
    int numProcs = Environment.ProcessorCount;
    int remainingWorkItems = numProcs;
    int nextIteration = inclusiveLowerBound;
    using (ManualResetEvent mre = new ManualResetEvent(false))
    {
        // Create each of the work items.
        for (int p = 0; p < numProcs; p++)
        {
            ThreadPool.QueueUserWorkItem(delegate
            {
                int index;
                while ((index = Interlocked.Increment(ref nextIteration) - 1) < exclusiveUpperBound)
                    body(index);

                if (Interlocked.Decrement(ref remainingWorkItems) == 0)
                    mre.Set();
            });
        }
        // Wait for all threads to complete.
        mre.WaitOne();
    }
}

Parallel.For возвращает тип значения ParallelLoopResult, который содержит сведения о завершенном цикле.Одна из его перегрузок выглядит следующим образом:

public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);

Важно понимать, что параллельное выполнение не всегда быстрее, чем последовательное выполнение.Чтобы решить, использовать ли параллель или нет, вы должны оценить рабочую нагрузку, которая будет выполняться на итерацию цикла.Если фактическая работа, выполняемая циклом, мала по сравнению со стоимостью синхронизации потока, лучше использовать обычный цикл.

Это один из примеров, когда последовательный цикл для производительности быстрее параллельного:

static void Main(string[] args)
{
    Action<int> action = new Action<int>(SimpleMethod);

    // ordinary For loop performance estimation
    var sw = Stopwatch.StartNew();

    for(int i = 0; i < 1000; i++)
        action(i);

    Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);

    // parallel For loop performance estimation
    sw = Stopwatch.StartNew();

    Parallel.For(0, 1000, action);

    Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);
}

static void SimpleMethod(int index)
{
    int d = 1;
    int result = index / d;
}

Выход:

0.0001963 sec.
0.0346729 sec.
0 голосов
/ 15 сентября 2010

Цитирование FAQ по SQLite: ' Потоки злые .Избегайте их '

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

Некоторые оптимизируют код пользовательского интерфейса так, чтобы он реагировал на микросекунды, а не на миллисекунды, явно не имея значения и вызывая большой ущерб.

...