2011-02-04 27 views
13

ACTUALIZACIÓN: utilicé Threading para dividir el Loop en la Cantidad de Kernels (8 en mi Case) y el Loop completo pasó en menos de 1 segundo. Entonces, el problema no es que la Operación no sea más rápida con el enhebrado. ¿Por qué Parralel Extension falló en este caso?Parallel.Foreach tan rápido/lento como normal ForEach

Hola a todos. Quiero convertir mi ForEach con Parrallel.Foreach. El problema es que la parralelisation apenas aporta ninguna ventaja para mí.

original:

foreach (Entities.Buchung buchung in buchungen) { 
    Int32 categoryID = manager.GetCategoryID(new Regelengine.Booking(buchung)); // Average 4ms 
    buchung.Category = categoryID.ToString(); 
} 

paralelas:

System.Threading.Tasks.Parallel.ForEach(buchungen, buchung => { 
    Int32 categoryID = manager.GetCategoryID(new Regelengine.Booking(buchung)); 
    buchung.Category = categoryID.ToString(); 
}); 

Resultados:

--------------------------- 
Stopwatched Results for 1550 entries in the List: 
--------------------------- 
Parallel.Foreach 00:00:07.6599066 
Average Foreach: 00:00:07.9791303 

Tal vez el problema es, que la acción real en el bucle es tan corto? Pero nadie puede decirme que la paralelización de las 1550 operaciones en un Intel I7 no ahorrará tiempo.

+0

Probablemente hay un bloqueo en esa cosa 'Regelengine'. – leppie

+2

La pregunta es: ¿el método dentro de la declaración se beneficia del paralelismo? Lo siguiente que no sé es qué hace GetCategoryID. ¿Hay una llamada a la base de datos que podría ser el cuello de botella y evitar que el código use multihilo? – sprinter252

+2

¿Qué sucede en el método 'manager.GetCategoryID'? ¿Qué sucede en el ctor 'new Regelengine.Booking'? – AakashM

Respuesta

9

Sólo hay un recurso que puede aprovechar al utilizar Paralelo.Para: ciclos de CPU. Cuando tienes N núcleos, teóricamente puedes acelerar tu código por un factor de N. Lo que sí se requiere es que en realidad sean los ciclos de la CPU la restricción de tu código. Lo cual no es a menudo el caso a menos que ejecutes código computacionalmente caro. Otras restricciones son la velocidad del disco duro, la conexión de red, un servidor dbase, en algunos casos, el ancho de banda del bus de memoria. Solo tienes uno, Paralelo. Porque mágicamente no puedo darte otro disco.

La prueba de si Parallel.For acelera su código es bastante simple. Simplemente ejecute el código sin paralelismo y observe la carga de la CPU en Taskmgr.exe o Perfmon. Si un núcleo no se ejecuta al 100%, entonces su código no se computará. Si se está ejecutando a, por ejemplo, 10%, entonces solo puedes esperar hacerlo el 90% del tiempo sin importar cuántos núcleos tengas. Lo cual obtendrá superponiendo el tiempo de espera de E/S con el tiempo de procesamiento, dos hilos lo harán.

5

Preguntas que debe considerar en este son:

  • ¿Cuál es la sobrecarga de hacer girar un hilo?
  • ¿Cuál es la sobrecarga de seguridad de mi hilo (cerraduras)?
  • ¿Dónde están los cuellos de botella reales y el multihilo realmente ayudará?

La última es su mayor consideración aquí. Por ejemplo, si está maximizando su canal de E/S, todos los hilos del mundo no harán sentadillas. Entonces, ¿su tarea está vinculada a la CPU o a la E/S?

+0

La creación de subprocesos no debe ser lo suficientemente cara como para crear este efecto. Y decir bloqueos con decir dónde no es útil. –

+0

Gracias por su respuesta, pero usé Hilos normales ahora para dividir el bucle manualmente y se ejecutó en poco tiempo. Entonces, ¿el problema no está en el hilo sino en ForeachLoop? – Steav

1

Creo que tienes razón, parece un poco demasiado corto para que valga la pena usar foreach paralelo. Utilizo foreach paralelo solo cuando sé que va a haber algo importante sucediendo en el foreach que tomará tiempo, o podría llevar tiempo, como una conexión a la base de datos o si estoy enviando una gran cantidad de datos a un servicio web. Si solo está procesando información en el servidor, como obtener ID de una colección que ya ha sido cargada en la memoria, realmente no valdría la pena.

0

En primer lugar, 1550 no es mucho. Por ejemplo, ordenar una matriz de estos muchos elementos generalmente será más rápido cuando se hace secuencialmente que cuando se hace en paralelo. Todo depende de la operación.

En segundo lugar, ¿qué hace GetCategoryID? ¿Utiliza bloqueos? Para el caso, ¿el constructor Regelengine.Booking?

7 segundos el tiempo de ejecución total indica que la operación es lo suficientemente lenta como para que sea se beneficie de la paralelización. Por otro lado, su código parece indicar que en realidad no está ocurriendo mucho procesamiento aquí. Probablemente estés cargando datos del disco o de una base de datos. En ambos casos, eso es un cuello de botella que la paralelización puede hacer (casi) nada en contra. El procesamiento concurrente hace que su código sea más rápido solo si está computeado.

Pero no ha dado suficiente información para determinarlo.

1

Paralelo no será más rápido si no tiene núcleos disponibles para usar.Entonces, cuando veo código como este, lo primero que pienso es que tienes otros hilos en ejecución.

También podría ser la carga de trabajo. La lógica de sincronización no es gratuita y cada iteración no hace mucho. Considera mirar las otras sobrecargas de Parallel.ForEach para ver las opciones que puedes ajustar.

También intente utilizar Parallel.For. No puede leer desde un IEnumerable de forma paralela, pero puede hacerlo desde un IList utilizando índices.

Cuestiones relacionadas