异步操作 - MVC

3

我知道异步方法的逻辑,但是我不明白以下方法如何给我带来优势。以下异步方法和同步方法有什么区别吗?

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
    if (User.Identity.IsAuthenticated)
    {
        return RedirectToAction("Index", "Manage");
    }

    if (ModelState.IsValid)
    {
        var info = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (info == null)
        {
            return View("ExternalLoginFailure");
        }
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await UserManager.CreateAsync(user);
        if (result.Succeeded)
        {
            result = await UserManager.AddLoginAsync(user.Id, info.Login);
            if (result.Succeeded)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
                return RedirectToLocal(returnUrl);
            }
        }
        AddErrors(result);
    }

    ViewBag.ReturnUrl = returnUrl;
    return View(model);
}

2
是的。服务器不会阻塞等待数据库响应,而是释放线程进行其他工作。当数据库响应时,服务器在await之后继续处理。在具有中等流量的Web服务器上,这意味着可以通过相同数量的线程为更多请求提供服务。 - Panagiotis Kanavos
2
CPU使用率也会下降,因为阻塞操作不是无操作,您可以从性能监视器中注意到这一点。一方面,在线程进入睡眠之前,阻塞操作会开始自旋等待,从而浪费CPU。另一方面,操作系统必须检查每个正在睡眠的线程以查找哪个被解除阻塞。因此,您得到了无效的CPU负载。 - Panagiotis Kanavos
2
简而言之,异步操作允许您从同一硬件中提供更多的请求。 - Panagiotis Kanavos
所有的描述都非常清晰,我现在理解得更好了。 - Cer
1
@Cer:我写了一篇关于异步ASP.NET的文章,你可能会觉得很有用。它解释了为什么I/O的异步处理程序比同步处理程序更好,并配有漂亮的图片。 - Stephen Cleary
@StephenCleary 很棒的文章。谢谢你。 - Cer
2个回答

5
为了理解这种做法的好处,首先我们需要了解ASP.NET生命周期如何工作。
每次我们向服务器发出请求时,管道会检索线程池线程来处理它,并且像每个资源一样,线程池用于此目的的可用线程数是有限制的。
一些操作,例如I/O或数据库操作,通常会阻止处理过程,持续时间比预期长。
当管道达到可用资源的限制时,它所能做的就是等待某些资源被释放以便它可以处理新的请求。
当await/async方法开始运行时,由于其内部工作方式,运行时可以异步地处理这些任务,释放线程池线程以处理另一个请求,而前一个请求正在被阻塞。这通常会导致使用相同可用资源的更高总吞吐量,但每个单独请求的处理成本略高。 这里提供了一个简单的解释。
希望这可以帮助您。

2

异步方法在客户端看来不会有任何变化。它将是正常的http调用(几乎需要相同的时间来完成请求)。然而,您将在Web服务器上获得更好的扩展性。

例如,在您的代码中,每当有任何异步操作正在进行时,处理请求的工作线程将返回到线程池中。该线程可用于处理下一个请求。当异步操作完成后,线程将从线程池中选取以进行进一步处理。

var info = await AuthenticationManager.GetExternalLoginInfoAsync();

result = await UserManager.AddLoginAsync(user.Id, info.Login);

// and other async methods

为了测试这个api,您可以对其进行规模测试,并交叉检查异步控制器与同步控制器服务的调用数量。

有关更详细的信息: https://learn.microsoft.com/en-us/aspnet/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4

希望这有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接