2012-08-14 347 views
6

我想使用Task.WhenAll来等待多个任务的完成。如何正确使用Task.WhenAll()

我的代码如下 - 它应该启动多个异步任务,每个任务都检索总线路由,然后将它们添加到本地阵列。但是,Task.WhenAll(...)会立即返回,并且本地路由数组的计数为零。这看起来很奇怪,因为我期望每个Task中的各种'await'语句表示流程被暂停,并且任务在完成之前不会返回。

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

我明显做错了事 - 但是什么?

+0

你尝试检查是否最终'Task'不是处于故障状态? – 2012-08-14 10:33:35

+0

我认为它可能是错误的“等待调度程序”内部foreach循环。 UI线程将被观察并立即显示? – 2012-08-14 10:34:40

+0

@ie。是的,它的状态是RanToCompletion。数组中的所有任务的状态都是RanToCompletion,尽管当我实际检查它们时,每个的结果字段都是WaitingForActivation – 2012-08-14 10:46:42

回答

6

这是下降到一个缺乏基本的如何异步等待真正起作用的理解。

内部任务将流返回到外部任务,然后在等待返回之前完成。

为了达到我想要的东西,我需要重构如下:

 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 
     } 

由于Dave Smits

5

我怀疑问题是您拨打Task.Factory.StartNew()。我怀疑你结束了一个Task<Task>,你只有当它有效地发现开始的任务。

试试这个:

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

谢谢。我假设我的方法的其余部分会像以前一样继续,即将任务添加到任务数组中,然后调用数组上的Task.WhenAll(...)。在这种情况下,这种方法与我答案中的方法相比如何?有什么优势吗? – 2012-08-14 11:05:41

+0

@CarlosP:说实话,我真的没有足够的上下文来评论哪种方法更好。但是,是的,其余的方法会像以前一样继续。 – 2012-08-14 11:13:50