2012-08-14 19 views
6

Estoy tratando de usar la Tarea.Cuando todos esperan la finalización de múltiples tareas.Cómo usar Task.WhenAll() correctamente

Mi código está a continuación: se supone que debe iniciar varias tareas asíncronas, cada una de las cuales recupera una ruta de bus y luego las agrega a una matriz local. Sin embargo, Task.WhenAll (...) devuelve inmediatamente y el recuento de la matriz de rutas locales es cero. Esto parece extraño, ya que esperaría que las diversas declaraciones 'en espera' dentro de cada tarea signifiquen que el flujo está suspendido y la tarea no regresará hasta que haya finalizado.

 List<Task> monitoredTasks = new List<Task>(); 
     foreach (BusRouteIdentifier bri in stop.services) 
     { 
      BusRouteRequest req = new BusRouteRequest(bri.id); 

      // Start a new task to fetch the route for each stop 
      Task getRouteTask = Task.Factory.StartNew(async() => 
      { 
       var route = await BusDataProviderManager.DataProvider.DataBroker.getRoute(req); 

        // Add the route to our array (on UI thread as it's observed) 
        await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate 
        { 
         this.routes.Add(route); 
        }); 
      }); 

      // Store the task in our monitoring list 
      monitoredTasks .Add(getRouteTask); 
     } 

     Debug.WriteLine("Awaiting WHENALL"); 
     await Task.WhenAll(monitoredTasks); 
     Debug.WriteLine(string.Format("WHENALL returned (routes count is {0} ", this.routes.Count)); 

     this.OnWillEndFetchingRoutes(new EventArgs()); 

Obviamente estoy haciendo algo mal - pero ¿qué?

+0

has comprobar si la final 'Task' no está en el estado de fallo? –

+0

Creo que podría ser algo malo 'esperar despachador' dentro de foreach loop. El hilo de UI se observará y se mostrará de inmediato? –

+0

@ie. Sí, su estado es RanToCompletion. El estado de todas las tareas del conjunto también es RanToCompletion, aunque cuando las inspecciono individualmente, el campo Resultado de cada una de ellas está en WaitingForActivation –

Respuesta

6

esto era por una falta básica de entendimiento de cómo asíncrono esperar realmente funciona.

La tarea interna era devolver el flujo a la tarea externa, que luego finalizaba antes de que volviera la espera.

Para lograr lo que quería, lo que necesitaba refactor de la siguiente manera:

 List<Task<BusRoute>> routeRetrievalTasks = new List<Task<BusRoute>>(); 
     foreach (BusRouteIdentifier bri in stop.services) 
     { 
      BusRouteRequest req = new BusRouteRequest(bri.id); 
      routeRetrievalTasks.Add(BusDataProviderManager.DataProvider.DataBroker.getRoute(req)); 
     } 

     foreach (var task in routeRetrievalTasks) 
     { 
      var route = await task; 
      this.routes.Add(route); // triggers events 
     } 

Gracias a Dave Smits

5

Sospecho que el problema es su llamada a Task.Factory.StartNew(). Sospecho que terminas con un Task<Task>, y solo estás averiguando cuándo es efectivamente comenzada la tarea.

Tal vez puedas probar:

Func<Task> taskFunc = async() => 
{ 
    var route = await BusDataProviderManager.DataProvider.DataBroker.getRoute(req); 

    // Add the route to our array (on UI thread as it's observed) 
    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate 
    { 
     this.routes.Add(route); 
    }); 

} 

Task getRouteTask = Task.Run(taskFunc); 
+0

Gracias. Supongo que el resto de mi método continuaría como antes, es decir, agregaría la tarea a la matriz de tareas, luego llamaría Task.WhenAll (...) en la matriz. En ese caso, ¿cómo se compara este enfoque con el de mi respuesta? ¿Hay alguna ventaja? –

+0

@CarlosP: para ser sincero, realmente no tengo suficiente contexto para comentar cuál es el mejor enfoque. Pero sí, el resto de tu método continuaría como antes. –

Cuestiones relacionadas