2015-05-25 89 views
1

我讀過很多帖子,人們面臨類似的問題,但他們似乎做出不適用的假設或他們的代碼根本不適用於我。我需要結合異步方法的結果。 我想要的唯一的異步是結果的組合。由於Azure服務總線一次只允許我抓取256條消息,因此我想發送多個請求以一次獲得幾個批次,並將其製作成一個列表。結合異步方法和同步返回

似乎是,如果你調用一個異步 方法要返回給調用者的假設而完成的各項工作 (即:需要長時間運行的任務)。但是,我根本不需要這個。我 想等待任務完成,然後把我的組合列表 並返回它。

首先,我不想用async標記我的調用方法。我可以,但爲什麼我應該,我無意中調用了一個同步方法,在返回給我之前恰好執行一些異步操作。

我看過使用WhenAll()然後使用Result的例子,但這對我不起作用。我嘗試了所有不同的排列,但它會鎖定我的應用程序,或者它告訴我任務尚未執行。

這是我目前有:

public IEnumerable<BrokeredMessage>[] GetCombinedResults() 
{ 
      var job =() => ServiceBus.TrackerClient.ReceiveBatchAsync(BatchLimit); 
      Task<IEnumerable<BrokeredMessage>> task1 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job); 
      Task<IEnumerable<BrokeredMessage>> task2 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job); 
      IEnumerable<BrokeredMessage>[] results = Task.WhenAll<IEnumerable<BrokeredMessage>>(task1, task2).Result; 
      return results; 
} 

但調用的結果導致其鎖定。我已經讀過這樣的僵局,但是在其他問題上已經看到了這個問題。 如果我調用Task.WaitAll()並且不在意結果,這種類型的設置工作正常。不知道爲什麼當我想要從任務返回結果時變得困難。我嘗試過使用Task.Run,​​但是在獲得結果之前它會退出我的方法。

回答

5

您似乎對使用異步進行扇出並行感興趣。這是一個完全有效的事情。沒有必要使整個調用鏈異步,以利用扇出並行。

你偶然發現了通常的ASP.NET死鎖。您可以使用Task.Run作爲一種簡單的,故障安全的方式來避免它。首先,讓我們GetCombinedResults異步保持它的簡單和一致的:

public async Task<IEnumerable<BrokeredMessage>[]> GetCombinedResultsAsync() 
{ 
      var job =() => ServiceBus.TrackerClient.ReceiveBatchAsync(BatchLimit); 
      Task<IEnumerable<BrokeredMessage>> task1 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job); 
      Task<IEnumerable<BrokeredMessage>> task2 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job); 
      IEnumerable<BrokeredMessage>[] results = await Task.WhenAll<IEnumerable<BrokeredMessage>>(task1, task2); 
      return results; 
} 

這種方法顯然是正確的。它不混合同步和異步。這樣稱呼:

var results = Task.Run(() => GetCombinedResultsAsync()).Result; 

這個原理的工作原理是GetCombinedResultsAsync現在沒有同步上下文執行。

+0

謝謝!我仍然得到異步/等待的東西。我仍然不確定爲什麼WaitAll()非常簡單。我不需要await關鍵字,我不必將當前方法標記爲async。我只是創建一些任務並說WaitAll()。如果我想在突然完成任務後得到結果,我必須將當前方法標記爲異步。似乎很奇怪。 – KingOfHypocrites

+0

我不知道爲什麼WaitAll可以工作。它不應該。 Task.Run的東西肯定應該工作。使用調試器找出掛起開始的代碼段。或者,註釋Task.Run行,看它是否可行。還有一些你還沒有發佈的相關代碼。張貼更多的代碼。 – usr

+0

@KingOfHypocrites:WaitAll()阻止當前線程等待所有任務完成,因此根據同步上下文(UI和Asp.NET)可能會發生死鎖。 usr解決方案在執行異步方法時刪除同步上下文。請參閱[this](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html)和[this](https://msdn.microsoft.com/en-us/雜誌/ gg598924.aspx)可以很好地解釋同步上下文。 – Absolom