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

недавно я переехал в C#.net 4.

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

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

3 ответов


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

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


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

общее представление о том, как параллельный.Для работ можно представить следующим образом:

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();
    }
}

параллельный.Для возвращает 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.

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

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

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