¿Qué hace MaxDegreeOfParallelism?

Estoy usando Parallel.ForEach y estoy haciendo algunas actualizaciones de bases de datos, ahora sin configurar MaxDegreeOfParallelism, una máquina de procesador de doble núcleo da como resultado tiempos de espera de cliente sql, donde la máquina procesadora de cuatro núcleos de alguna manera no agota el tiempo de espera.

Ahora no tengo control sobre qué tipo de núcleos de procesador están disponibles donde se ejecuta mi código, pero ¿hay alguna configuración que pueda cambiar con MaxDegreeOfParallelism que probablemente ejecute menos operaciones simultáneamente y no provoque tiempos de espera?

Puedo boost los tiempos de espera pero no es una buena solución, si en una CPU más baja puedo procesar menos operaciones simultáneamente, eso pondrá menos carga en la CPU.

Ok, he leído todas las otras publicaciones y también a MSDN, pero si establezco MaxDegreeOfParallelism en un valor inferior, ¿sufrirá mis máquinas de cuatro núcleos?

Por ejemplo, ¿hay alguna forma de hacer algo así como, si la CPU tiene dos núcleos, entonces use 20, si la CPU tiene cuatro núcleos y luego 40?

La respuesta es que es el límite superior para toda la operación en paralelo, independientemente del número de núcleos.

Por lo tanto, incluso si no usa la CPU porque está esperando IO o un locking, no se ejecutarán tareas adicionales en paralelo, solo el máximo que especifique.

Para descubrir esto, escribí este fragmento de código de prueba. Hay un locking artificial para estimular al TPL a usar más hilos. Lo mismo sucederá cuando su código esté esperando IO o base de datos.

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

Si no especifico MaxDegreeOfParallelism, el registro de la consola muestra que se ejecutan hasta 8 tareas al mismo tiempo. Me gusta esto:

 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 

Comienza más bajo, aumenta con el tiempo y al final intenta ejecutar 8 al mismo tiempo.

Si lo limito a algún valor arbitrario (digamos 2), obtengo

 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 

Ah, y esto es en una máquina quadcore.

Por ejemplo, ¿hay alguna forma de hacer algo así como, si la CPU tiene dos núcleos, entonces use 20, si la CPU tiene cuatro núcleos y luego 40?

Puede hacer esto para que el paralelismo dependa de la cantidad de núcleos de CPU:

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

Sin embargo, las CPU más nuevas tienden a usar hyper-threading para simular núcleos adicionales. Entonces, si tiene un procesador de cuatro núcleos, Environment.ProcessorCount probablemente lo informará como 8 núcleos. Descubrí que si configuras el paralelismo para tener en cuenta los núcleos simulados, en realidad ralentiza otros hilos, como los hilos UI.

Entonces, aunque la operación finalizará un poco más rápido, una IU de la aplicación puede experimentar un retraso significativo durante este tiempo. Dividir el `Environment.ProcessorCount ‘por 2 parece lograr las mismas velocidades de procesamiento al tiempo que mantiene la CPU disponible para los subprocesos de UI.

Parece que el código que está ejecutando en paralelo es de locking, lo que significa que a menos que pueda encontrar y solucionar el problema que está causando eso, no debe paralicularlo en absoluto.

establece el número de hilos para ejecutar en paralelo …