Was ist der Vorteil der Verwendung von Async mit MVC5?


120

Was ist der Unterschied zwischen:

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

und:

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

Ich sehe, dass der MVC-Code jetzt asynchron ist, aber was ist der Unterschied. Gibt einer eine viel bessere Leistung als der andere? Ist es einfacher, Probleme mit dem einen als mit dem anderen zu debuggen? Sollte ich Änderungen an anderen Controllern vornehmen, damit meine Anwendung Async hinzufügt?


In den allermeisten Situationen gibt es keinen ernsthaften Vorteil für die Verwendung von Async in MVC, es gibt jedoch viele
Nachteile

1
@ChrisMarisic - Eines der schwerwiegendsten: Sie können ReaderWriterLock oder eines der anderen Synchronisationsprimitive (außer Semaphore) nicht verwenden.
Quarkly

Antworten:


170

Die asynchronen Aktionen sind nur nützlich, wenn Sie E / A-gebundene Vorgänge ausführen, z. B. Remoteserveraufrufe. Der Vorteil des asynchronen Aufrufs besteht darin, dass während des E / A-Vorgangs kein ASP.NET-Arbeitsthread verwendet wird. So funktioniert das erste Beispiel:

  1. Wenn eine Anforderung die Aktion ausführt, nimmt ASP.NET einen Thread aus dem Thread-Pool und beginnt mit der Ausführung.
  2. Die IdentityManager.Authentication.CheckPasswordAndSignInMethode wird aufgerufen. Dies ist ein blockierender Aufruf -> während des gesamten Aufrufs wird der Worker-Thread gefährdet.

Und so funktioniert der zweite Anruf:

  1. Wenn eine Anforderung die Aktion ausführt, nimmt ASP.NET einen Thread aus dem Thread-Pool und beginnt mit der Ausführung.
  2. Das IdentityManager.Authentication.CheckPasswordAndSignInAsyncwird aufgerufen und kehrt sofort zurück. Ein E / A-Abschlussport wird registriert und der ASP.NET-Arbeitsthread wird für den Thread-Pool freigegeben.
  3. Später, wenn der Vorgang abgeschlossen ist, wird der E / A-Abschlussport signalisiert und ein weiterer Thread aus dem Thread-Pool gezogen, um die Rückgabe der Ansicht abzuschließen.

Wie Sie im zweiten Fall sehen können, werden ASP.NET-Arbeitsthreads nur für einen kurzen Zeitraum verwendet. Dies bedeutet, dass im Pool mehr Threads verfügbar sind, um andere Anforderungen zu bearbeiten.

Verwenden Sie daher abschließend nur dann asynchrone Aktionen, wenn Sie eine echte asynchrone API haben. Wenn Sie innerhalb einer asynchronen Aktion einen blockierenden Anruf tätigen, können Sie den gesamten Nutzen daraus ziehen.


Wie wäre es mit Kontextsynchronisation? Wird dies nicht ein derartiger Aufwand sein, dass Sie überhaupt keine asynchronen Aktionen verwenden möchten? "Der Overhead einer asynchronen Methode, die tatsächlich asynchron ausgeführt wird, hängt vollständig davon ab, ob Threads mithilfe von SynchronizationContext.Post gewechselt werden müssen. Wenn dies der Fall ist, wird der Overhead von dem Thread-Switch dominiert, den sie bei der Wiederaufnahme ausführt. Dies bedeutet, dass der aktuelle SynchronizationContext ausgeführt wird ein großer Unterschied." (Async in C # 5.0, 2012, Alex Davies)
annemartijn

1
@Darin Warum ist es so wichtig, den Haupt-Thread freizugeben? Sind die Threads begrenzt?
Omtechguy

1
@Omtechguy Eine bessere Lösung besteht darin, Nicht-ASP.NET-Anforderungen auf ein CDN zu verschieben. Ein einfaches CDN verwendet lediglich eine Subdomain und einen separaten App-Pool für physische Dateien wie Javascript und Bilder. Alternativ können Sie NgineX / Lighttpd / Apache für Dateien verwenden, oder Sie können einen Drittanbieter-Service wie Akamai (König für CDN, aber am teuersten)
Chris Marisic

Ich bin immer noch verwirrt. Wenn das CheckPasswordAndSignInAsyncaufgerufen wird, nimmt ASP.NET einen anderen Thread aus dem Thread-Pool und beginnt mit der Ausführung, nicht wahr? Wenn nicht, wo wird es checking password procedureausgeführt?
KevinBui

2

Normalerweise wird eine einzelne HTTP-Anforderung von einem einzelnen Thread verarbeitet, wodurch dieser Thread vollständig aus dem Pool entfernt wird, bis eine Antwort zurückgegeben wird. Mit der TPL sind Sie nicht an diese Einschränkung gebunden. Jede eingehende Anforderung startet eine Fortsetzung mit jeder Recheneinheit, die erforderlich ist, um eine Antwort zu berechnen, die auf einem beliebigen Thread im Pool ausgeführt werden kann. Mit diesem Modell können Sie viel mehr gleichzeitige Anforderungen verarbeiten als mit Standard-ASP.Net.

Ob es sich um eine neue Aufgabe handelt, die erzeugt wird oder nicht, und ob sie erwartet werden sollte oder nicht. Denken Sie immer an diese 70 ms, was ca. die max. Zeit, die ein Methodenaufruf dauern sollte. Wenn es länger ist, wird Ihre Benutzeroberfläche höchstwahrscheinlich nicht sehr reaktionsschnell sein.


0

In Webanwendungen, in denen beim Start eine große Anzahl gleichzeitiger Anforderungen angezeigt wird oder die eine hohe Last aufweisen (bei der die Parallelität plötzlich zunimmt), erhöht das asynchrone Ausführen dieser Webdienstaufrufe die Reaktionsfähigkeit Ihrer Anwendung. Die Verarbeitung einer asynchronen Anforderung dauert genauso lange wie die einer synchronen Anforderung. Wenn eine Anforderung beispielsweise einen Webdienstaufruf ausführt, dessen Abschluss zwei Sekunden dauert, dauert die Anforderung zwei Sekunden, unabhängig davon, ob sie synchron oder asynchron ausgeführt wird. Während eines asynchronen Aufrufs wird ein Thread jedoch nicht daran gehindert, auf andere Anforderungen zu antworten, während er auf den Abschluss der ersten Anforderung wartet. Daher verhindern asynchrone Anforderungen das Anfordern von Warteschlangen und das Wachstum des Thread-Pools, wenn viele gleichzeitige Anforderungen vorliegen, die lang laufende Vorgänge aufrufen.


Wenn Ihre Aspnet-Anwendung größtenteils aus Aufrufen anderer Webserver besteht, verhalten Sie sich größtenteils als "Gateway" / "Proxy", und Async ist für diesen Zweck hilfreich.
Chris Marisic
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.