Могу ли я заблокировать асинхронный код в ядре MVC?

#c# #async-await #asp.net-core-mvc

#c# #асинхронное ожидание #asp.net-core-mvc

Вопрос:

Мы все знаем известное сообщение в блоге Стивена Клири о блокировке асинхронного кода. В MVC 5 следующий код блокируется при запросе Home/Index :

 public class HomeController : Controller
{
    public string Index()
    {
        var model = AsyncMethod();
        return model.Resu<
    }

    private async Task<string> AsyncMethod()
    {
        await Task.Run(() => Thread.Sleep(2000));
        return "Hello";
    }
}
  

Однако точно такой же код не приводит к взаимоблокировке в веб-приложении ядра MVC. Ответ возвращает привет. Почему? Позволяет ли ядро MVC запускать несколько потоков одновременно в одном контексте запроса? Устарела ли фраза «Не блокировать асинхронный код» при разработке в ядре MVC?

Ответ №1:

Почему?

ASP.NET Ядро расположено async сверху вниз и рассчитано на максимальную скорость.

В рамках редизайна, ASP.NET команда смогла удалить все AspNetSynchronizationContext полностью. Некоторые аспекты ASP.NET контекст запроса был перенесен в ядро .NET, а другие были просто удалены (например, HttpContext.Current ).

Позволяет ли ядро MVC запускать несколько потоков одновременно в одном контексте запроса?

Нет. Однако понятие «контекст запроса» больше не представлено контекстом синхронизации.

Устарела ли кодовая фраза Don’t Block on Async при разработке в ядре MVC?

Нет. Это не приведет к тупику на ASP.NET Ядро, но ты все равно не должен этого делать.

«Могу ли я заблокировать асинхронный код в ядре MVC?» Да. «Должен ли я блокировать асинхронный код в ядре MVC?» Нет.

Комментарии:

1. Для тех из вас, кто хотел бы получить более подробное объяснение, ознакомьтесь с этим сообщением в блоге Стивена — blog.stephencleary.com/2017/03 /.

Ответ №2:

Этот код

 await Task.Run(() => Thread.Sleep(2000));
  

возможно, это не очень удачный шаблон, но он не «блокирует» в том смысле, на который ссылается сообщение Стивена. Чтобы сравнить яблоки с яблоками, вам нужно будет сделать это:

 private string BlockingAsyncMethod()
{
    Task.Run(() => Thread.Sleep(2000)).Wait();
    return "Hello";
}
  

Блокировка на Wait() or .Result — это большой запрет для MVC 5. Насколько мне известно, это все еще правильный совет для ядра MVC.

Комментарии:

1. Ваш пример не приводит к взаимоблокировке в ядре MVC. Я все еще получаю «Привет»

2. @Kapol блокирует!= взаимоблокировка. Блокировка относится к синхронному ожиданию результата операции. Взаимоблокировки иногда возникают, когда вы блокируете синхронно ( Wait() например, с помощью) асинхронную операцию. Важно отметить, что даже при плохом шаблоне (синхронизация через асинхронность) взаимоблокировки возникают не всегда .

3. Извини, Нейт, конечно, я имел в виду тупик. Дело в том, что, насколько я понимаю, мой пример всегда приводил к тупиковой ситуации в MVC 5, тогда как я не могу воспроизвести это поведение хотя бы один раз в ядре MVC.

4. Кроме того, изначально мой асинхронный метод вызывал асинхронную операцию MongoDB, которая, вероятно, очень близка к тому, что Стивен описал в своем блоге.