Qual é a vantagem do uso assíncrono com MVC5?

120

Qual é a diferença entre:

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

Vejo que o código MVC agora tem assíncrono, mas qual é a diferença. Um oferece desempenho muito melhor que o outro? É mais fácil depurar problemas com um do que com o outro? Devo fazer alterações em outros controladores para que meu aplicativo adicione o Async?

annemartijn
fonte
Na grande maioria das situações não há benefício grave para a utilização assíncrona em MVC, no entanto, existem muitos negativos
Chris Marisic
1
@ ChrisMarisic - Uma das mais graves: você não pode usar o ReaderWriterLock ou qualquer outra primitiva de sincronização (exceto o Semaphore).
Quarkly

Respostas:

170

As ações assíncronas são úteis apenas quando você está executando operações vinculadas de E / S, como chamadas de servidor remoto. O benefício da chamada assíncrona é que, durante a operação de E / S, nenhum thread de trabalho do ASP.NET está sendo usado. Então, aqui está como o primeiro exemplo funciona:

  1. Quando uma solicitação atinge a ação, o ASP.NET pega um thread do pool de threads e começa a executá-lo.
  2. O IdentityManager.Authentication.CheckPasswordAndSignInmétodo é chamado. Esta é uma chamada de bloqueio -> durante toda a chamada, o segmento de trabalho está sendo comprometido.

E aqui está como a segunda chamada funciona:

  1. Quando uma solicitação atinge a ação, o ASP.NET pega um thread do pool de threads e começa a executá-lo.
  2. O IdentityManager.Authentication.CheckPasswordAndSignInAsyncchamado é retornado imediatamente. Uma porta de conclusão de E / S é registrada e o thread de trabalho do ASP.NET é liberado para o pool de threads.
  3. Mais tarde, quando a operação é concluída, a porta de Conclusão de E / S é sinalizada, outro encadeamento é retirado do conjunto de encadeamentos para concluir o retorno da visualização.

Como você pode ver no segundo caso, os threads de trabalho do ASP.NET são usados ​​apenas por um curto período de tempo. Isso significa que há mais threads disponíveis no pool para atender a outras solicitações.

Portanto, para concluir, use ações assíncronas apenas quando você tiver uma API assíncrona verdadeira. Se você fizer uma chamada de bloqueio em uma ação assíncrona, estará matando todo o benefício dela.

Darin Dimitrov
fonte
Que tal sincronização de contexto. Não será uma sobrecarga tão grande que você não deseja usar ações assíncronas? "A sobrecarga de um método assíncrono que realmente é executado de forma assíncrona depende inteiramente da necessidade de alternar threads usando SynchronizationContext.Post. Se o fizer, a sobrecarga será dominada pela opção de thread que ele executa à medida que é reiniciado. Isso significa que o atual SynchronizationContext faz uma grande diferença." (Async em C # 5.0, 2012, Alex Davies)
annemartijn
1
@Darin Por que é tão importante liberar o thread principal? O segmento é limitado?
Omtechguy
1
@Omtechguy, uma solução melhor é mover solicitações que não são do ASP.NET para uma CDN. Uma CDN simples está apenas usando o subdomínio e o pool de aplicativos separado para arquivos físicos como seu javascript e imagens. Alternativamente, você pode usar NgineX / Lighttpd / Apache para arquivos, ou você pode usar um serviço de terceiros como Akamai (rei por CDN, mas mais caro)
Chris Marisic
Eu continuo confuso. Quando CheckPasswordAndSignInAsyncchamado, o ASP.NET pega outro thread do pool de threads e começa a executá-lo, não é? Se não, onde é checking password procedureexecutado?
KevinBui
2

Normalmente, uma única solicitação HTTP seria tratada por um único encadeamento, removendo completamente esse encadeamento do pool até que uma resposta seja retornada. Com o TPL, você não está vinculado por essa restrição. Qualquer solicitação recebida inicia uma continuação com cada unidade de cálculo necessária para calcular uma resposta capaz de executar em qualquer encadeamento no conjunto. Com esse modelo, você pode lidar com muito mais solicitações simultâneas do que com o ASP.Net padrão.

Se é alguma nova tarefa que será gerada, ou não, e se deve ser aguardada ou não. Pense sempre nesses 70 ms, que são aprox. o max. tempo que qualquer chamada de método deve levar. Se for mais longo, sua interface do usuário provavelmente não sentirá muito responsividade.

Gaurang Dhandhukiya
fonte
0

Em aplicativos da web que veem um grande número de solicitações simultâneas na inicialização ou têm uma carga estourada (onde a concorrência aumenta repentinamente), fazer essas chamadas de serviço da Web assíncronas aumentará a capacidade de resposta do seu aplicativo. Uma solicitação assíncrona leva a mesma quantidade de tempo para processar como uma solicitação síncrona. Por exemplo, se uma solicitação faz uma chamada de serviço da web que requer dois segundos para ser concluída, a solicitação leva dois segundos, seja executada de forma síncrona ou assíncrona. No entanto, durante uma chamada assíncrona, um encadeamento não é impedido de responder a outras solicitações enquanto aguarda a conclusão da primeira solicitação. Portanto, solicitações assíncronas impedem o enfileiramento de solicitações e o crescimento do conjunto de encadeamentos quando há muitas solicitações simultâneas que invocam operações de execução longa.

Muhammad Essa
fonte
Se o seu aplicativo aspnet consistir principalmente em chamadas para outros servidores Web, você estará se comportando como um 'gateway' / 'proxy' e o assíncrono será útil para esse fim.
Chris Marisic