¿Cuáles son las diferencias entre usar Parallel.ForEach o Task.Run () para iniciar un conjunto de tareas de forma asincrónica?
Versión 1:
List<string> strings = new List<string> { "s1", "s2", "s3" };
Parallel.ForEach(strings, s =>
{
DoSomething(s);
});
Versión 2:
List<string> strings = new List<string> { "s1", "s2", "s3" };
List<Task> Tasks = new List<Task>();
foreach (var s in strings)
{
Tasks.Add(Task.Run(() => DoSomething(s)));
}
await Task.WhenAll(Tasks);
c#
async-await
parallel.foreach
Petter T
fuente
fuente

Task.WaitAlllugar deTask.WhenAll.Respuestas:
En este caso, el segundo método esperará asincrónicamente a que se completen las tareas en lugar de bloquearlas.
Sin embargo, hay una desventaja de usar
Task.Runen un bucleParallel.ForEach: hay unaPartitionerque se crea para evitar realizar más tareas de las necesarias.Task.Runsiempre realizará una única tarea por elemento (ya que está haciendo esto), pero losParallellotes de clase funcionan, por lo que crea menos tareas que el total de elementos de trabajo. Esto puede proporcionar un rendimiento general significativamente mejor, especialmente si el cuerpo del bucle tiene una pequeña cantidad de trabajo por elemento.Si este es el caso, puede combinar ambas opciones escribiendo:
Tenga en cuenta que esto también se puede escribir en esta forma más corta:
fuente
DoSomethinges asíasync void DoSomething?async Task DoSomething?La primera versión bloqueará sincrónicamente el hilo de llamada (y ejecutará algunas de las tareas en él).
Si es un subproceso de interfaz de usuario, esto congelará la interfaz de usuario.
La segunda versión ejecutará las tareas de forma asincrónica en el grupo de subprocesos y liberará el subproceso de llamada hasta que estén listas.
También hay diferencias en los algoritmos de programación utilizados.
Tenga en cuenta que su segundo ejemplo se puede acortar a
fuente
await Task.WhenAll(strings.Select(async s => await Task.Run(() => DoSomething(s)));? Tuve problemas al devolver tareas (en lugar de esperar), especialmente cuando las declaraciones comousingestaban involucradas para deshacerse de los objetos.Terminé haciendo esto, ya que me pareció más fácil de leer:
fuente
He visto Parallel.ForEach usado inapropiadamente, y pensé que un ejemplo en esta pregunta ayudaría.
Cuando ejecute el código a continuación en una aplicación de consola, verá cómo las tareas ejecutadas en Parallel.ForEach no bloquean el hilo de llamada. Esto podría estar bien si no le importa el resultado (positivo o negativo) pero si necesita el resultado, debe asegurarse de usar Task.WhenAll.
Aquí está el resultado:
Conclusión:
El uso de Parallel.ForEach con una tarea no bloqueará el hilo de llamada. Si te importa el resultado, asegúrate de esperar las tareas.
~ Saludos
fuente