c# - Cuándo utilizar OrderByCompletion(Jon Skeet) frente a Parallel.ForEach con delegados asíncronos
async-await c#-5.0 (2)
Recientemente, Jon Skeet en NDC London habló sobre C # 5 async / await y presentó la idea de " ordenar por finalización " una lista de tareas asíncronas. Un enlace http://msmvps.com/blogs/jon_skeet/archive/2012/01/16/eduasync-part-19-ordering-by-completion-ahead-of-time.aspx
Estoy un poco confundido o debería decir que no estoy seguro de cuándo será más apropiada esta técnica.
No puedo entender la diferencia entre este y el siguiente ejemplo
var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, async item =>
{
// some pre stuff
var response = await GetData(item);
bag.Add(response);
// some post stuff
}
o ForEachAsync como explica Stephen Toub - http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx
EDIT: encontró una publicación de blog de Stephen Toub que explica "Ordenar por finalización" <=> "Procesar tareas a medida que se completan". Vale la pena leer. Después de leer esto, pude entender claramente las razones de cómo funciona y también cuándo utilizar esta técnica.
Parallel.ForEach(myCollection, async item =>
Esto es casi seguro que no es lo que quieres. El delegado tiene el tipo Action<T>
, por lo que el método anónimo es un método async void
. Eso significa que se inicia y no hay forma de verificar su estado, salvo verificando cualquiera de sus efectos secundarios. En particular, si algo sale mal, no puede detectar y manejar la excepción.
Sin embargo, suponiendo que nada va mal, los resultados se agregarán a la bag
medida que se completen. Hasta que se complete cualquier cosa, la bag
estará vacía.
Por el contrario, OrderByCompletion
devuelve IEnumerable<Task<T>>
que contiene inmediatamente todas las tareas aún no terminadas. Puede await
el quinto elemento y continuar cuando se completen cinco tareas. Esto podría ser útil cuando, por ejemplo, desea ejecutar una gran cantidad de tareas y actualizar periódicamente un formulario para mostrar el progreso.
La tercera opción que dio, ForEachAsync
, se comportaría como ForEach
, excepto que lo haría bien, sin los problemas mencionados anteriormente.
No use
Parallel.ForEach
para ejecutar el códigoasync
.Parallel.ForEach
no entiendeasync
, por lo que su lambda se convertirá enasync void
, lo que no funcionará correctamente (Parallel.ForEach
regresará antes de que todo el trabajo haya terminado, las excepciones no se manejarán correctamente, posiblemente otros problemas).Use algo como
ForEachAsync()
cuando tenga una colección de objetos (noTask
), desee realizar alguna acciónasync
para cada uno de ellos y las acciones se deben ejecutar en paralelo.Use
OrderByCompletion()
cuando tiene una colección deTask
, desea realizar alguna acción (asíncrona o no) para el resultado de cadaTask
, las acciones no deben ejecutarse en paralelo y desea ejecutar las acciones según el orden en que laTask
está completa.