Qual è il vantaggio di utilizzare async con MVC5?


120

Qual è la differenza tra:

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

e:

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

Vedo che il codice MVC ora è asincrono ma qual è la differenza. Uno offre prestazioni molto migliori dell'altro? È più facile eseguire il debug dei problemi con uno rispetto all'altro? Devo apportare modifiche ad altri controller per la mia applicazione per aggiungere Async?


Nella stragrande maggioranza delle situazioni non c'è alcun vantaggio serio nell'usare l'asincronia in MVC, tuttavia ci sono molti
aspetti

1
@ChrisMarisic - Una delle più serie: non puoi usare ReaderWriterLock o nessuna delle altre primitive di sincronizzazione (eccetto Semaphore).
Quarkly

Risposte:


170

Le azioni asincrone sono utili solo quando si eseguono operazioni di I / O associate come le chiamate al server remoto. Il vantaggio della chiamata asincrona è che durante l'operazione di I / O non viene utilizzato alcun thread di lavoro ASP.NET. Quindi ecco come funziona il primo esempio:

  1. Quando una richiesta raggiunge l'azione, ASP.NET prende un thread dal pool di thread e inizia a eseguirlo.
  2. Il IdentityManager.Authentication.CheckPasswordAndSignInmetodo viene richiamato. Questa è una chiamata di blocco -> durante l'intera chiamata il thread di lavoro viene compromesso.

Ed ecco come funziona la seconda chiamata:

  1. Quando una richiesta raggiunge l'azione, ASP.NET prende un thread dal pool di thread e inizia a eseguirlo.
  2. La IdentityManager.Authentication.CheckPasswordAndSignInAsyncsi chiama che restituisce immediatamente. Viene registrata una porta di completamento I / O e il thread di lavoro ASP.NET viene rilasciato al pool di thread.
  3. Successivamente, al termine dell'operazione, viene segnalata la porta di completamento I / O, un altro thread viene disegnato dal pool di thread per terminare la restituzione della visualizzazione.

Come puoi vedere nel secondo caso i thread di lavoro ASP.NET vengono utilizzati solo per un breve periodo di tempo. Ciò significa che ci sono più thread disponibili nel pool per servire altre richieste.

Quindi, per concludere, usa le azioni asincrone solo quando hai una vera API asincrona all'interno. Se effettui una chiamata di blocco all'interno di un'azione asincrona, ne stai uccidendo l'intero vantaggio.


Che ne dici della sincronizzazione del contesto. Non sarà un tale sovraccarico da non voler utilizzare affatto azioni asincrone? "L'overhead di un metodo asincrono che viene effettivamente eseguito in modo asincrono dipende interamente dalla necessità di cambiare thread utilizzando SynchronizationContext.Post. In tal caso, l'overhead è dominato dall'interruttore di thread che esegue quando riprende. Ciò significa che l'attuale SynchronizationContext fa una grande differenza." (Async in C # 5.0, 2012, Alex Davies)
annemartijn

1
@Darin Perché è così importante rilasciare il thread principale? I thread sono limitati?
Omtechguy

1
@Omtechguy una soluzione migliore è spostare le richieste non ASP.NET su un CDN. Un semplice CDN utilizza semplicemente un sottodominio e un pool di app separato per file fisici come javascript e immagini. In alternativa potresti usare NgineX / Lighttpd / Apache per i file, oppure potresti usare un servizio di terze parti come Akamai (re per CDN ma più costoso)
Chris Marisic

Sono ancora confuso. Quando CheckPasswordAndSignInAsyncviene chiamato, ASP.NET prende un altro thread dal pool di thread e inizia a eseguirlo, non è vero? In caso contrario, dove viene checking password procedureeseguita?
KevinBui

2

Normalmente, una singola richiesta HTTP verrebbe gestita da un singolo thread, rimuovendo completamente quel thread dal pool fino a quando non viene restituita una risposta. Con il TPL, non sei vincolato da questo vincolo. Qualsiasi richiesta in arrivo avvia una continuazione con ogni unità di calcolo richiesta per calcolare una risposta in grado di essere eseguita su qualsiasi thread nel pool. Con questo modello è possibile gestire molte più richieste simultanee rispetto a ASP.Net standard.

Se si tratta di una nuova attività che verrà generata o meno e se dovrebbe essere attesa o meno. Pensa sempre a quei 70 ms, che sono ca. il max. tempo che dovrebbe richiedere qualsiasi chiamata al metodo. Se è più lungo, molto probabilmente la tua interfaccia utente non sarà molto reattiva.


0

Nelle applicazioni Web che vedono un gran numero di richieste simultanee all'avvio o hanno un carico eccessivo (dove la concorrenza aumenta improvvisamente), rendere asincrone queste chiamate di servizi Web aumenterà la reattività dell'applicazione. Una richiesta asincrona richiede la stessa quantità di tempo per l'elaborazione di una richiesta sincrona. Ad esempio, se una richiesta effettua una chiamata al servizio Web che richiede due secondi per essere completata, la richiesta richiede due secondi indipendentemente dal fatto che venga eseguita in modo sincrono o asincrono. Tuttavia, durante una chiamata asincrona, a un thread non viene impedito di rispondere ad altre richieste mentre attende il completamento della prima richiesta. Pertanto, le richieste asincrone impediscono l'accodamento delle richieste e la crescita del pool di thread quando sono presenti molte richieste simultanee che richiamano operazioni di lunga durata.


Se la tua applicazione aspnet consiste in gran parte di chiamate ad altri server web, ti comporti in gran parte come un 'gateway' / 'proxy' e async è utile a tale scopo.
Chris Marisic
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.