2015-06-25 5 views
-1

У меня есть метод async, который возвращает строку xml. Когда я добавляю задачу в список задач, она запускает задачу, но зависает при первом ожидании при разговоре с базой данных с использованием Entity Framework. Ниже приведен пример кода.async Task Freezes When Calling EF Async Methods

public async Task<ActionResult> GenerateXml(long id) 
{ 
    var tasks = new List<Task<string>>(); 
    tasks.Add(GenerateXmlAsync(id)); 
    Task.WaitAll(tasks.ToArray()); 
} 

private async Task<string> GenerateXmlAsync(long id) 
{ 
    using (var dbContext = new MyDatabaseContext()) 
    { 
     var item = await dbContext.Items.FirstOrDefaultAsync(itm => itm.Id = id); 
     /* do some calculations, generate the xml... */ 
     var xml = "<generated by code above>"; 
     return xml; 
    } 
} 

Использование потоковых журналов на Azure, я могу видеть, что задание выполняется, но никогда не делает это мимо метода асинхронной DbContext. Есть ли причина, по которой это может повесить?

+0

проблемы с подключением ... можете ли вы его отладить? –

+0

Если я изменил 'FirstOrDefaultAsync' на' FirstOrDefault' и удалил 'await', он отлично работает. –

+0

Обязательная ссылка, чтобы избежать взаимоблокировок: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx – ken2k

ответ

2

Если ваш код блокирует асинхронный код, это subject to a deadlock situation. Я описываю это в полной мере на моем блоге, но общая суть является:

  • Когда await дает вызывающий поток, по умолчанию это первый захватит «контекст». Обычно это контекст пользовательского интерфейса (для приложений пользовательского интерфейса), контекст запроса ASP.NET (для серверных приложений) или контекст пула потоков.
  • Когда ожидаемая операция завершается, конечный автомат async возобновляет выполнение, планируя себя в этом контексте. Таким образом, методы async в потоке пользовательского интерфейса возобновятся в этом потоке пользовательского интерфейса, а методы async, обрабатывающие запрос ASP.NET, снова будут обрабатывать один и тот же запрос ASP.NET.
  • Некоторые контексты (например, контексты пользовательского интерфейса и контексты запросов ASP.NET) позволяют только один поток за раз. Итак, если есть поток заблокирован в этом контексте, то метод async будет ждать этот поток перед возобновлением. В этом случае поток блокируется, ожидая завершения метода async, чего он не может сделать, так как он ожидает заблокированный поток. Классический тупик.

Вы также можете найти мое async intro сообщение полезное. В конце у меня есть список «старых способов блокировки вещей» (чего следует избегать) вместе с «новыми асинхронными способами выполнения вещей». Соответствующим примером в этом случае является замена Task.WaitAll на await Task.WhenAll.

+0

. Именно поэтому использование 'WaitAll' блокировало поток, который был открыт при ожидании операции ввода-вывода, который должен был начаться в другом потоке. Использование 'waitait Task.WhenAll' исправило проблему. Благодаря! –