Что делает MaxDegreeOfParallelism?

Я использую параллельно.ForEach и я делаю некоторые обновления базы данных, теперь без установки MaxDegreeOfParallelism, двухъядерный процессор приводит к тайм-аутам клиента sql, где еще четырехъядерный процессор каким-то образом не тайм-аут.

теперь у меня нет контроля над тем, какие процессорные ядра доступны там, где работает мой код, но есть ли некоторые настройки, которые я могу изменить с помощью MaxDegreeOfParallelism, который, вероятно, будет запускать меньше операций одновременно и не приведет к тайм-ауты?

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

Ok Я прочитал все другие сообщения и MSDN тоже, но установка MaxDegreeOfParallelism на более низкое значение заставит мои четырехъядерные машины страдать?

например, есть ли в любом случае, чтобы сделать что-то вроде, если CPU имеет два ядра, а затем использовать 20, если CPU имеет четыре ядра, то 40?

4 ответов


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

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

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

class Program
{
    static void Main(string[] args)
    {
        var locker = new Object();
        int count = 0;
        Parallel.For
            (0
             , 1000
             , new ParallelOptions { MaxDegreeOfParallelism = 2 }
             , (i) =>
                   {
                       Interlocked.Increment(ref count);
                       lock (locker)
                       {
                           Console.WriteLine("Number of active threads:" + count);
                           Thread.Sleep(10);
                        }
                        Interlocked.Decrement(ref count);
                    }
            );
    }
}

Если я не указываю MaxDegreeOfParallelism, журнал консоли показывает, что одновременно выполняется до 8 задач. Вот так:

Number of active threads:6
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:6
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7
Number of active threads:7

Он начинается ниже, увеличивается с течением времени, и в конце он пытается запустить 8 одновременно.

Если я ограничу его некоторым произвольным значением (скажем, 2), я получу

Number of active threads:2
Number of active threads:1
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2
Number of active threads:2

О, и это на машине quadcore.


например, есть ли в любом случае, чтобы сделать что-то вроде, если CPU имеет два ядра, а затем использовать 20, если CPU имеет четыре ядра, то 40?

вы можете сделать это, чтобы сделать параллелизм зависимым от количества ядер процессора:

var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(sourceCollection, options, sourceItem =>
{
    // do something
});

однако новые процессоры, как правило, используют hyper-threading для имитации дополнительных ядер. Так что если у вас четырехъядерный процессор, то Environment.ProcessorCount вероятно, сообщит об этом как 8 ядер. Я обнаружил, что если вы установите параллелизм для учета смоделированные ядра, то это фактически замедляет другие потоки, такие как потоки пользовательского интерфейса.

поэтому, хотя операция завершится немного быстрее, пользовательский интерфейс приложения может испытывать значительное отставание в течение этого времени. Разделив среду.ProcessorCount ' by 2, похоже, достигает той же скорости обработки, сохраняя при этом процессор доступным для потоков пользовательского интерфейса.


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


задает количество потоков для параллельного выполнения...