2015-05-25 3 views
1

Я читал много сообщений, в которых люди сталкивались с подобными проблемами, но они, похоже, делают предположения, которые не применяются, или их код просто не работает для меня. Мне нужно совместить результаты асинхронных методов. ТОЛЬКО вещь async, которую я хочу, это объединение результатов. Поскольку Azure Service Bus позволяет мне одновременно получать 256 сообщений, я хочу отправить несколько запросов, чтобы получить сразу несколько партий и сделать их одним списком.Объединить результаты метода асинхронного и синхронного возврата

Там, кажется, предположение, что если вы вызываете метод асинхронной вы хотите вернуться к абоненту в то время как работа завершена (т.е .: некоторые давно запущенной задачи). Тем не менее, я не хочу этого вообще. I хотите подождать завершения задач, а затем взять мой объединенный список и вернуть его.

Во-первых, я не хочу отмечать мой метод вызова асинхронным способом. Я могу, но почему я должен, я обязательно использую синхронный метод, который выполняет некоторые асинхронные действия, прежде чем возвращаться ко мне.

Я видел примеры с использованием метода WhenAll(), а затем работал с результатом, но это не работает для меня. Я пробовал все разные перестановки, но он либо блокирует мое приложение, либо говорит, что задача еще не выполнена.

Вот что я в настоящее время:

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

Вы, кажется, заинтересованы в использовании async для разветвления параллелизма. Это абсолютно правильная вещь. Нет необходимости, чтобы вся цепочка асинхронных вызовов использовала параллельный параллелизм.

Вы наткнулись на обычный тупик 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(). Если я хочу получить результаты после завершения задач, я должен пометить текущий метод как async. Кажется странным. – 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) и [это] (https://msdn.microsoft.com/en-us/ журнал/gg598924.aspx) для хорошего объяснения контекста синхронизации. – Absolom

Смежные вопросы