2009-11-28 14 views
7

Supongamos que tengo una tarea vinculada a IO. Estoy usando WithDegreeOfParallelism = 10 y WithExecution = ForceParallelism mode, pero la consulta solo usa dos hilos. ¿Por qué?¿Por qué PLINQ usa solo dos hilos?

Entiendo que PLINQ usualmente elegirá un grado de paralelismo igual a mi conteo de núcleos, pero ¿por qué ignora mi solicitud específica de mayor paralelismo?

static void Main(string[] args) 
{ 
    TestParallel(0.UpTo(8)); 
} 

private static void TestParallel(IEnumerable<int> input) 
{ 
    var timer = new Stopwatch(); 
    timer.Start(); 
    var size = input.Count(); 

    if (input.AsParallel(). 
     WithDegreeOfParallelism(10). 
     WithExecutionMode(ParallelExecutionMode.ForceParallelism). 
     Where(IsOdd).Count() != size/2) 
     throw new Exception("Failed to count the odds"); 

    timer.Stop(); 
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds"); 
} 

private static bool IsOdd(int n) 
{ 
    Thread.Sleep(1000); 
    return n%2 == 1; 
} 
+2

¿Cuántos procesadores/núcleos tiene? – LukeH

+2

Dos. Pero especifiqué específicamente que el grado de paralelismo es 10. – ripper234

+0

Si tiene una tarea enlazada de E/S y ejecutarla en múltiples hilos en paralelo mejora la velocidad, entonces probablemente no estaba realmente ligada a E/S, en primer lugar, estaba mal escrito (lecturas sincronizadas en lugar de asincrónicas, por ejemplo). –

Respuesta

8

PLINQ trata de encontrar el número óptimo de hilos para llevar a cabo lo que queremos que haga lo más rápido posible, si sólo tiene 2 núcleos en la CPU, ese número es más probable 2. Si tuvo una quad core, es más probable que veas 4 subprocesos, pero la creación de 4 subprocesos en una máquina de doble núcleo realmente no mejoraría el rendimiento, ya que solo 2 subprocesos podrían estar activos al mismo tiempo.

Además, con operaciones basadas en IO, es probable que cualquier subproceso adicional se bloquee simplemente en la primera operación de IO realizada.

+4

Realmente no responde mi pregunta: ¿por qué elige usar dos hilos a pesar de que solicito específicamente un grado de paralelismo = 10? (Pregunta actualizada) – ripper234

+3

@ ripper234: De la documentación de MSDN: "El grado de paralelismo es el ** máximo ** número de tareas de ejecución simultáneas que se utilizarán para procesar la consulta". 'WithDegreeOfParallelism' es solo una sugerencia de que PLINQ debe usar * no más * que * hilos * n *. http://msdn.microsoft.com/en-us/library/dd383719%28VS.100%29.aspx – LukeH

+3

Entonces ... ¿no hay forma de usar PLINQ de manera efectiva para las tareas vinculadas a IO? – ripper234

4

10 es máxima

Ajusta el grado de paralelismo de usar en una consulta. El grado de paralelismo es el número máximo de tareas de ejecución simultáneas que se usarán para procesar la consulta.

A partir de aquí:

MSDN

+0

Por defecto, PLINQ usa todos los procesadores en la computadora host hasta un máximo de ** 64 **. Puede indicar a PLINQ que no use más de un número específico de procesadores utilizando el método WithDegreeOfParallelism (Ofource). http://msdn.microsoft.com/en-us/library/dd383719.aspx –

2

Parece PLINQ sintoniza el número de hilos. Cuando envolví el código anterior en un ciclo while (verdadero), las dos primeras iteraciones tardaron dos segundos en ejecutarse, pero el tercero y el anterior tomaron solo un segundo. PLINQ entendió que los núcleos están inactivos y aumentó el número de subprocesos. ¡Impresionante!

+1

Tenga en cuenta que para que esto suceda, realmente debe especificar WithDegreeOfParallelism; de lo contrario, PLINQ se limitaría a la cantidad de núcleos en su máquina. – ripper234

0

Estoy de acuerdo con Rory, excepto con IO. No se ha probado con el disco IO, pero la red IO definitivamente puede ser más efectiva con más hilos, que núcleos en la CPU.

prueba simple (sería más correcto funcionamiento de prueba con cada hilo contar varias veces, como velocidad de la red no es constante, pero aún así) para demostrar que:

[Test] 
    public void TestDownloadThreadsImpactToSpeed() 
    { 
     var sampleImages = Enumerable.Range(0, 100) 
      .Select(x => "url to some quite large file from good server which does not have anti DSS stuff.") 
      .ToArray();    

     for (int i = 0; i < 8; i++) 
     { 
      var start = DateTime.Now; 
      var threadCount = (int)Math.Pow(2, i); 
      Parallel.For(0, sampleImages.Length - 1, new ParallelOptions {MaxDegreeOfParallelism = threadCount}, 
         index => 
          { 
           using (var webClient = new WebClient()) 
           { 
            webClient.DownloadFile(sampleImages[index], 
                  string.Format(@"c:\test\{0}", index)); 
           } 
          }); 

      Console.WriteLine("Number of threads: {0}, Seconds: {1}", threadCount, (DateTime.Now - start).TotalSeconds); 
     } 
    } 

Resultado imagen 500x500px del CDN con usando la máquina 8 núcleo con SSD fue:

Número de hilos: 1, segundos: 25.3904522
Número de hilos: 2, segundos: 10.8986233
Número de hilos: 4, segundos: 9.9325681
Número de hilos: 8, segundos: 3.7352137
Número de hilos: 16, segundos: 3.3071892
Número de hilos: 32, segundos: 3.1421797
Número de hilos: 64, segundos: 3.1161782
Número de hilos: 128, segundos: 3,7272132

el último resultado tiene tal vez que pienso en primer lugar porque tenemos que descargar hasta 100 imágenes :)

diferencias horarias utilizando 8-64 hilos no es tan grande, pero que se encuentra en 8 máquina de núcleo.Si se tratara de una máquina de 2 núcleos (portátil de usuario final barato), creo que forzar el uso de 8 hilos tendría más impacto, que en la máquina de 8 núcleos forzar el uso de 64 hilos.

+0

¿Ha promediado estos números en, por ejemplo, 10.000 iteraciones? – ChrisF

+0

He mencionado, que sería más correcto ejecutar la prueba con cada número de hilos varias veces. De todos modos, el punto es forzar más hilos para las máquinas, que tienen bajo recuento de CPU, en caso de que esté haciendo IO de red. – Giedrius

+0

Parece que las opciones paralelas se ignoran para> = 8. Agregue algunos resultados de depuración dentro del cuerpo paralelo y creo que verá que solo se está ejecutando un máximo de 8 a la vez y está acelerando. – crokusek