40

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

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

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

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

Например, есть ли что-то вроде, если у процессора есть два ядра, а затем использовать 20, если у процессора четыре ядра, а затем 40?

ответ

58

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

Таким образом, даже если вы не используете 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 машине.

+0

У моей логики нет ожиданий или ввода-вывода, она просто обновляет SQL, да SQL может иметь свои собственные, но в основном я жду завершения SQL. Каков максимальный ток по умолчанию для активных потоков? –

+0

По умолчанию 2 на ядро, но TPL может повысить это, если ваш код не использует CPU. В большинстве баз данных имеется некоторое количество ввода-вывода. –

+1

Если моя 6-ядерная машина сильно загружена, она использует только 1 или 2 потока. Если он слегка загружен, он доходит до 12. Его достаточно интеллектуальный, чтобы учитывать существующую системную нагрузку. – Contango

-1

он устанавливает число потоков параллельно идущий ...

+0

Учитывается ли он? –

+0

в основном, какой db вы используете? – SolidSnake

+0

Одинаковая операционная система, одна и та же программа, одни и те же данные (главным образом, репликаторы), но одна из них - высокопроизводительная машина с двухъядерным ядром, а две простые двухъядерные машины, одна и та же программа извлекает данные с других серверов и сохраняет данные обратно в SQL (много капли и изображения). –

1

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

+0

-1 Вопрос не в параллельном или не параллельном, его простое, что SQL выполняет свои собственные вычисления, но слишком много параллельных запросов делает тайм-аут клиента, я хочу запустить меньше операций. Deadlock не является проблемой как четырехъядерный процессор с той же логикой, тот же SQL работает нормально, я не хочу продолжать увеличивать таймаут. –

+0

Вы пробовали увеличить тайм-аут и подтвердили, что он работает? Проблемы с параллелизмом могут быть чрезвычайно утонченными, и многие вещи могут привести к их исчезновению и появлению, по-видимому, случайным образом. Тот факт, что он работал на другой машине с большим количеством ядер, не означает, что он не сломан, или что больше средств помогло. – jimrandomh

+0

Увеличение таймаута помогает. Но почему-то использование ЦП составляет более 50% на небольших машинах, а на больших машинах - менее 5%, теперь я нахожусь в точке, где мне нужно выяснить проблему производительности, и есть ли что-то, что я могу сделать, чтобы изменить код или просто нужно для обновления процессора. –

13

Например, есть ли что-то вроде, если процессор имеет два ядра, а затем использовать 20, если у процессора четыре ядра, а затем 40?

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

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

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

Итак, хотя операция завершится немного быстрее, пользовательский интерфейс приложения может испытывать значительное отставание в течение этого времени. Разделение «Environment.ProcessorCount» на 2, похоже, достигает одинаковой скорости обработки, сохраняя при этом ЦПУ доступным для потоков пользовательского интерфейса.

Смежные вопросы