How to use Task.WhenAll () correctly

I am trying to use Task.WhenAll to wait for several tasks to complete.

My code is below - it is supposed to run several async tasks, each of which extracts the bus route, and then adds them to the local array. However, Task.WhenAll (...) returns immediately, and the number of arrays of local routes is zero. This seems strange, since I would expect that the various statements β€œwait” in each task mean that the thread is paused and the task will not return until it is finished.

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 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()); 

I'm obviously doing something wrong, but what?

+6
source share
2 answers

This was due to a lack of understanding of how async is waiting.

The inner task returned the thread to the outer task, which then completed before the wait ever returned.

In order to achieve what I wanted, I had to reorganize the following:

  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 } 

Thanks Dave Smits

+6
source

I suspect the problem is in your call to Task.Factory.StartNew() . I suspect you are ending with Task<Task> , and you will only know when it effectively started the task.

Try this instead:

 Func<Task> taskFunc = async () => { var route = await BusDataProviderManager.DataProvider.DataBroker.getRoute(req); // Add the route to our array (on UI thread as it observed) await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate { this.routes.Add(route); }); } Task getRouteTask = Task.Run(taskFunc); 
+5
source

Source: https://habr.com/ru/post/922821/


All Articles