В чем преимущество использования async с MVC5?

120

В чем разница между:

public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        IdentityResult result = IdentityManager.Authentication.CheckPasswordAndSignIn(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
        if (result.Success)
        {
            return Redirect("~/home");
        }
        else
        {
            AddErrors(result);
        }
    }
    return View(model);
}

и:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        IdentityResult result = await IdentityManager.Authentication.CheckPasswordAndSignInAsync(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
        if (result.Success)
        {
            return Redirect("~/home");
        }
        else
        {
            AddErrors(result);
        }
    }
    return View(model);
}

Я вижу, что код MVC теперь имеет асинхронный режим, но в чем разница. Один дает лучшую производительность, чем другой? Легче ли отлаживать проблемы с одним, чем с другим? Следует ли мне вносить изменения в другие контроллеры моего приложения, чтобы добавить Async?

annemartijn
источник
В подавляющем большинстве ситуаций нет серьезных преимуществ от использования async в MVC, однако есть много недостатков,
Крис Марисич
1
@ChrisMarisic - один из самых серьезных: нельзя использовать ReaderWriterLock или какие-либо другие примитивы синхронизации (кроме Semaphore).
Quarkly,

Ответы:

170

Асинхронные действия полезны только тогда, когда вы выполняете связанные операции ввода-вывода, такие как вызовы удаленного сервера. Преимущество асинхронного вызова заключается в том, что во время операции ввода-вывода рабочий поток ASP.NET не используется. Итак, вот как работает первый пример:

  1. Когда запрос попадает в действие, ASP.NET берет поток из пула потоков и начинает его выполнение.
  2. Вызывается IdentityManager.Authentication.CheckPasswordAndSignInметод. Это блокирующий вызов -> во время всего вызова рабочий поток подвергается опасности.

А вот как работает второй вызов:

  1. Когда запрос попадает в действие, ASP.NET берет поток из пула потоков и начинает его выполнение.
  2. IdentityManager.Authentication.CheckPasswordAndSignInAsyncНазывается , который немедленно возвращается. Порт завершения ввода-вывода регистрируется, и рабочий поток ASP.NET выпускается в пул потоков.
  3. Позже, когда операция завершается, порт завершения ввода-вывода получает сигнал, из пула потоков выводится другой поток, чтобы завершить возврат представления.

Как видите, во втором случае рабочие потоки ASP.NET используются только в течение короткого периода времени. Это означает, что в пуле доступно больше потоков для обслуживания других запросов.

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

Дарин Димитров
источник
Как насчет синхронизации контекста. Разве это не будет такой накладной работой, что вы вообще не захотите использовать асинхронные действия? "Накладные расходы асинхронного метода, который фактически выполняется асинхронно, полностью зависит от того, нужно ли ему переключать потоки с помощью SynchronizationContext.Post. Если это так, накладные расходы зависят от переключения потоков, которое он выполняет при возобновлении. Это означает, что текущий контекст SynchronizationContext делает большая разница ". (Асинхронность в C # 5.0, 2012 г., Alex Davies)
annemartijn
1
@Darin Почему так важно выпустить основную ветку? Ограничены ли потоки?
Omtechguy
1
@Omtechguy - лучшее решение - переместить запросы, отличные от ASP.NET, в CDN. Простой CDN просто использует поддомен и отдельный пул приложений для физических файлов, таких как ваш javascript и изображения. В качестве альтернативы вы можете использовать NgineX / Lighttpd / Apache для файлов, или вы можете использовать сторонний сервис, такой как Akamai (король для CDN, но самый дорогой)
Крис Марисич,
Я все еще в замешательстве. Когда CheckPasswordAndSignInAsyncвызывается, ASP.NET берет другой поток из пула потоков и начинает его выполнение, не так ли? Если нет, то где checking password procedureвыполняется?
KevinBui
2

Обычно один HTTP-запрос обрабатывается одним потоком, полностью удаляя этот поток из пула до тех пор, пока не будет возвращен ответ. В случае TPL вы не связаны этим ограничением. Любой поступающий запрос запускает продолжение с каждой единицей вычислений, необходимой для вычисления ответа, который может выполняться в любом потоке в пуле. С помощью этой модели вы можете обрабатывать намного больше одновременных запросов, чем со стандартным ASP.Net.

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

Гауранг Дхандукия
источник
0

В веб-приложениях, которые видят большое количество одновременных запросов при запуске или имеют скачкообразную нагрузку (когда параллелизм резко возрастает), выполнение этих вызовов веб-служб асинхронными повысит скорость отклика вашего приложения. Асинхронный запрос обрабатывается столько же, сколько и синхронный. Например, если запрос выполняет вызов веб-службы, для выполнения которого требуется две секунды, запрос занимает две секунды, независимо от того, выполняется он синхронно или асинхронно. Однако во время асинхронного вызова поток не блокируется от ответа на другие запросы, пока он ожидает завершения первого запроса. Следовательно, асинхронные запросы предотвращают создание очереди запросов и рост пула потоков, когда существует много одновременных запросов, которые вызывают длительные операции.

Мухаммад Эсса
источник
Если ваше приложение aspnet в основном состоит из обращений к другим веб-серверам, вы в значительной степени ведете себя как «шлюз» / «прокси», и для этой цели полезен асинхронный режим.
Крис Марисич