2013-07-26 58 views
1

我有一個稱爲VehicleInfoFetcher抽象類,異步從WebClient通過此方法返回信息:異步/等待 - 我是否正確運行這些方法並行?

public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID); 

我想這個類的兩個分開的實例的結果組合,結合之前運行的每個並聯結果。這是在第三類,CombinedVehicleInfoFetcher(本身也是VehicleInfoFetcher的子類)完成的。

這是我的代碼 - 但我不太相信它正在並行運行任務;我做對了嗎?它可以優化嗎?

public class CombinedVehicleInfoFetcher : VehicleInfoFetcher 
    { 
     public HashSet<VehicleInfoFetcher> VehicleInfoFetchers { get; set; } 

     public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID) 
     { 
      // Create a list of parallel tasks to run 
      var resultTasks = new List<Task<DTOrealtimeinfo>>(); 
      foreach (VehicleInfoFetcher fetcher in VehicleInfoFetchers) 
       resultTasks.Add(fetcher.getVehicleInfo(stopID, stopID2, timePointLocal)); 

      // run each task 
      foreach (var task in resultTasks) 
       await task; 

      // Wait for all the results to come in 
      await Task.WhenAll(resultTasks.ToArray()); 

      // combine the results 
      var allRealtimeResults = new List<DTOrealtimeinfo>(resultTasks.Select(t => t.Result) ); 
      return combineTaskResults(allRealtimeResults); 
     } 

     DTOrealtimeinfo combineTaskResults(List<DTOrealtimeinfo> realtimeResults) 
     { 
      // ... 


      return rtInfoOutput; 
     } 

    } 

編輯

一些非常有用的答案,這裏是一個重新編寫例子來幫助討論,下面USR:

 public override async Task<object> combineResults() 
     { 
      // Create a list of parallel tasks to run 
      var resultTasks= new List<object>(); 
      foreach (AnotherClass cls in this.OtherClasses) 
       resultTasks.Add(cls.getResults()); 

      // Point A - have the cls.getResults() methods been called yet? 

      // Wait for all the results to come in 
      await Task.WhenAll(resultTasks.ToArray()); 

      // combine the results 
      return new List<object>(resultTasks.Select(t => t.Result) ); 
     } 
    } 

回答

2

幾乎所有的任務開始時已經開始。可能無論fetcher.getVehicleInfo退貨是否已經開始。所以,你可以刪除:

 // run each task 
     foreach (var task in resultTasks) 
      await task; 

Task.WhenAll速度更快,具有更好的錯誤行爲(您想所有的異常被傳播,不只是你第一次發生在跌倒)。

此外,等待不會啓動任務。它等待完成。你必須安排單獨開始的任務,但正如我所說,幾乎所有的任務已經開始,當你得到它們。這也是最佳做法。


爲了幫助在評論我們的討論:

Task Test1() { return new Task(() => {}); } 
Task Test2() { return Task.Factory.StartNew(() => {}); } 
Task Test3() { return new FileStream("").ReadAsync(...); } 
Task Test4() { return new TaskCompletionSource<object>().Task; } 
  1. 是否從方法返回時,不「跑」。必須開始。糟糕的做法。
  2. 返回時運行。無論你用它做什麼,它已經在運行。沒有必要將其添加到列表或將其存儲在某個地方。
  3. 已經運行(2)。
  4. 跑步的概念在這裏沒有意義。儘管無法明確啓動,但這項任務永遠不會完成。
+0

我還是很困惑。你說'await'不會啓動Tasks,但是如果我要把單行'await getVehicleInfo(「foo」);'這會啓動任務,對吧? –

+0

不,任務已經開始。等待任務完成後纔會繼續執行。試試這個:'等待新的TaskCompletionSource ().Task'。這永遠不會完成,因爲任務永遠不會結束。旁註:await不會引入併發/線程。也許這是你所犯的錯誤?它所做的只是「邏輯等待」完成。 – usr

+0

如果你不說「等待」,任務仍然會同時運行。 – usr

相關問題