La primera es una opción mucho mejor.
Parallel.ForEach, internamente, utiliza a Partitioner<T>
para distribuir su colección en elementos de trabajo. No realizará una tarea por elemento, sino que la procesará por lotes para reducir la sobrecarga involucrada.
La segunda opción programará un solo Task
por artículo en su colección. Si bien los resultados serán (casi) los mismos, esto introducirá muchos más gastos generales de los necesarios, especialmente para grandes colecciones, y hará que los tiempos de ejecución generales sean más lentos.
Para su información: el Partitioner utilizado se puede controlar mediante el uso de las sobrecargas apropiadas para Parallel.ForEach , si así lo desea. Para más detalles, vea Particionadores personalizados en MSDN.
La principal diferencia, en tiempo de ejecución, es que el segundo actuará de forma asíncrona. Esto se puede duplicar usando Parallel.ForEach haciendo:
Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));
Al hacer esto, aún aprovecha los particionadores, pero no bloquee hasta que se complete la operación.
Hice un pequeño experimento para ejecutar un método "1,000,000,000 (mil millones)" veces con "Paralelo.Para" y uno con objetos "Tarea".
Medí el tiempo del procesador y encontré Parallel más eficiente. Paralelo: divide su tarea en pequeños elementos de trabajo y los ejecuta en todos los núcleos de forma paralela de manera óptima. Al crear muchos objetos de tarea (FYI TPL utilizará la agrupación de subprocesos internamente) moverá cada ejecución en cada tarea creando más estrés en el cuadro, lo que es evidente en el experimento a continuación.
También creé un pequeño video que explica TPL básico y también demostré cómo Parallel.For utiliza su núcleo de manera más eficiente http://www.youtube.com/watch?v=No7QqSc5cl8 en comparación con las tareas y subprocesos normales.
Experimento 1
Experimento 2
fuente
Mehthod1()
en este ejemplo?Parallel.ForEach optimizará (puede que ni siquiera inicie nuevos subprocesos) y bloqueará hasta que finalice el bucle, y Task.Factory creará explícitamente una nueva instancia de tarea para cada elemento, y regresará antes de que finalicen (tareas asincrónicas). Paralelo: Foreach es mucho más eficiente.
fuente
En mi opinión, el escenario más realista es cuando las tareas tienen que completar una operación pesada. El enfoque de Shivprasad se centra más en la creación de objetos / asignación de memoria que en la computación misma. Hice una investigación llamando al siguiente método:
La ejecución de este método lleva aproximadamente 0.5 segundos.
Lo llamé 200 veces usando Paralelo:
Luego lo llamé 200 veces usando la forma tradicional:
Primer caso completado en 26656 ms, el segundo en 24478 ms. Lo repetí muchas veces. Cada vez que el segundo enfoque es marginalmente más rápido.
fuente