c# async-await c#-5.0

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ódigo async . Parallel.ForEach no entiende async , por lo que su lambda se convertirá en async 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 (no Task ), desee realizar alguna acción async para cada uno de ellos y las acciones se deben ejecutar en paralelo.

  • Use OrderByCompletion() cuando tiene una colección de Task , desea realizar alguna acción (asíncrona o no) para el resultado de cada Task , las acciones no deben ejecutarse en paralelo y desea ejecutar las acciones según el orden en que la Task está completa.