Jaka jest zaleta używania async z MVC5?

120

Jaka jest różnica pomiędzy:

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);
}

i:

[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);
}

Widzę, że kod MVC ma teraz asynchroniczny, ale jaka jest różnica. Czy jeden zapewnia znacznie lepszą wydajność niż drugi? Czy łatwiej jest debugować problemy z jednym niż drugim? Czy powinienem wprowadzić zmiany w innych kontrolerach, aby moja aplikacja mogła dodać Async?

annemartijn
źródło
W zdecydowanej większości sytuacji nie ma poważnych korzyści z używania async w MVC, jednak jest wiele negatywów
Chris Marisic
1
@ChrisMarisic - jeden z najpoważniejszych: nie możesz użyć ReaderWriterLock ani żadnego z innych prymitywów synchronizacji (z wyjątkiem Semaphore).
Quarkly

Odpowiedzi:

170

Akcje asynchroniczne są przydatne tylko podczas wykonywania operacji związanych z we / wy, takich jak wywołania serwera zdalnego. Zaletą wywołania asynchronicznego jest to, że podczas operacji we / wy nie jest używany żaden wątek roboczy ASP.NET. Oto jak działa pierwszy przykład:

  1. Gdy żądanie trafia w akcję, ASP.NET pobiera wątek z puli wątków i rozpoczyna jego wykonywanie.
  2. IdentityManager.Authentication.CheckPasswordAndSignInMetoda jest wywoływana. To jest wywołanie blokujące -> podczas całego połączenia wątek roboczy jest zagrożony.

A oto jak działa drugie połączenie:

  1. Gdy żądanie trafia w akcję, ASP.NET pobiera wątek z puli wątków i rozpoczyna jego wykonywanie.
  2. Wywoływana IdentityManager.Authentication.CheckPasswordAndSignInAsyncjest funkcja, która natychmiast powraca. Rejestrowany jest port zakończenia we / wy, a wątek roboczy ASP.NET jest zwalniany do puli wątków.
  3. Później, gdy operacja zostanie zakończona, zostanie zasygnalizowany port zakończenia we / wy, inny wątek jest rysowany z puli wątków, aby zakończyć zwracanie widoku.

Jak widać w drugim przypadku wątki robocze ASP.NET są używane tylko przez krótki czas. Oznacza to, że w puli dostępnych jest więcej wątków do obsługi innych żądań.

Podsumowując, używaj akcji asynchronicznych tylko wtedy, gdy masz wewnątrz prawdziwy interfejs API asynchroniczny. Jeśli wykonasz połączenie blokujące w akcji asynchronicznej, zabijasz całą jego korzyść.

Darin Dimitrov
źródło
A co z synchronizacją kontekstów. Czy nie będzie to takie obciążenie, że nie chcesz w ogóle używać akcji asynchronicznych? „Narzut metody asynchronicznej, która w rzeczywistości jest wykonywana asynchronicznie, zależy całkowicie od tego, czy musi ona przełączać wątki za pomocą SynchronizationContext.Post. Jeśli tak, narzut jest zdominowany przez przełączanie wątków, które wykonuje podczas wznawiania. Oznacza to, że bieżący SynchronizationContext sprawia, że duża różnica." (Async w C # 5.0, 2012, Alex Davies)
annemartijn
1
@Darin Dlaczego uwolnienie głównego wątku jest takie ważne? Czy liczba wątków jest ograniczona?
Omtechguy
1
@ Omtechguy lepszym rozwiązaniem jest przenoszenie żądań innych niż ASP.NET do CDN. Prosta sieć CDN używa tylko subdomeny i oddzielnej puli aplikacji dla plików fizycznych, takich jak javascript i obrazy. Alternatywnie możesz użyć NgineX / Lighttpd / Apache do plików lub możesz użyć usługi innej firmy, takiej jak Akamai (król dla CDN, ale najdroższy)
Chris Marisic
Wciąż jestem zdezorientowany. Po CheckPasswordAndSignInAsyncwywołaniu ASP.NET pobiera inny wątek z puli wątków i zaczyna go wykonywać, prawda? Jeśli tak nie jest, gdzie jest checking password procedurewykonywany?
KevinBui
2

Zwykle pojedyncze żądanie HTTP byłoby obsługiwane przez jeden wątek, całkowicie usuwając ten wątek z puli, aż do zwrócenia odpowiedzi. Dzięki TPL nie jesteś związany tym ograniczeniem. Każde przychodzące żądanie rozpoczyna kontynuację z każdą jednostką obliczeniową wymaganą do obliczenia odpowiedzi, która może zostać wykonana w dowolnym wątku w puli. Dzięki temu modelowi możesz obsłużyć znacznie więcej jednoczesnych żądań niż w przypadku standardowego ASP.Net.

Czy pojawi się jakieś nowe zadanie, czy nie, i czy należy na nie czekać, czy nie. Zawsze myśl o tych 70 ms, czyli ok. max. czas, jaki powinno zająć wywołanie metody. Jeśli jest dłuższy, Twój interfejs użytkownika najprawdopodobniej nie będzie reagował zbyt szybko.

Gaurang Dhandhukiya
źródło
0

W aplikacjach internetowych, które widzą dużą liczbę równoczesnych żądań podczas uruchamiania lub mają gwałtowne obciążenie (gdzie współbieżność nagle wzrasta), asynchroniczne wywoływanie usług sieci Web zwiększy szybkość reakcji aplikacji. Przetwarzanie żądania asynchronicznego zajmuje tyle samo czasu, co żądanie synchroniczne. Na przykład, jeśli żądanie powoduje wywołanie usługi sieci Web, które wymaga dwóch sekund, aby zakończyć, żądanie zajmuje dwie sekundy, niezależnie od tego, czy jest wykonywane synchronicznie, czy asynchronicznie. Jednak podczas wywołania asynchronicznego wątek nie jest blokowany przed odpowiadaniem na inne żądania, gdy czeka na zakończenie pierwszego żądania. Dlatego żądania asynchroniczne zapobiegają kolejkowaniu żądań i wzrostowi puli wątków, gdy istnieje wiele współbieżnych żądań, które wywołują długotrwałe operacje.

Muhammad Essa
źródło
Jeśli Twoja aplikacja aspnet w dużej mierze składa się z wywołań do innych serwerów internetowych, w dużej mierze zachowujesz się jak „brama” / „serwer proxy”, a asynchronizacja jest do tego przydatna.
Chris Marisic,