【问题标题】:Why does an async single task run faster than a normal single task?为什么异步单任务运行速度比普通单任务快?
【发布时间】:2015-10-15 22:15:18
【问题描述】:

我有一个方法,它只有一个任务要做并且必须等待该任务完成:

public async Task<JsonResult> GetAllAsync()
{
    var result = await this.GetAllDBAsync();
    return Json(result, JsonRequestBehavior.AllowGet);
}

public async Task<List<TblSubjectSubset>> GetAllDBAsync()
{
    return await model.TblSubjectSubsets.ToListAsync();
}

它比我在没有异步等待的情况下运行它要快得多。 我们知道

async 和 await 关键字不会导致额外的线程 创建的。异步方法不需要多线程,因为异步 方法不在自己的线程上运行。该方法在当前运行 同步上下文并仅在线程上使用时间 方法处于活动状态

根据此链接:https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads。当我们没有另一个线程来处理这项工作时,速度更快的原因是什么?

【问题讨论】:

  • 你如何确定一个比另一个快?
  • 我已经测试过,异步方法的运行速度大约快了两倍
  • 请再次阅读我的评论。我问你,你是怎么得出这个结论的。你测量了什么?你是怎么测量的?如果没有这些信息,我们将无能为力。
  • 在客户端我签入时间轴 ajax 请求和服务器端我减去开始时间和结束时间
  • 请向我们展示“非异步”版本——但无论如何,9 毫秒与 17 毫秒的客户端时间不太可能是统计上显着的性能衡量标准。连接延迟、CPU 调度等方面的变化可能会导致更多的噪音。

标签: c# multithreading performance asynchronous


【解决方案1】:

我同意 Orbittman 的观点,他提到了应用程序架构所涉及的开销。它不能作为一个非常好的基准前提,因为您无法确定降级是否确实可以完全归因于异步调用与非异步调用。

我创建了一个非常简单的基准来粗略比较异步调用和同步调用,并且实际上在整个时序中每次异步都会丢失,尽管数据收集部分似乎总是以相同的方式结束。看看:https://gist.github.com/mattGuima/25cb7893616d6baaf970

话虽如此,关于架构的相同想法也适用。框架处理异步调用的方式不同:Async and await - difference between console, Windows Forms and ASP.NET

要记住的主要事情是永远不要将异步与性能增益混为一谈,因为它完全不相关,而且大多数情况下它根本不会导致任何增益,特别是对于受 CPU 限制的代码。请查看 Parallel 库。

【讨论】:

    【解决方案2】:

    “异步”不是意味着“更快”。

    “异步”是指“以在操作期间不需要线程的方式执行其操作,从而允许该线程用于其他工作。”

    在这种情况下,您正在测试单个请求。异步请求会将其线程“让出”给 ASP.NET 线程池……因为没有其他请求,所以它没有其他用途。

    我完全希望异步处理程序比同步处理程序运行。这是有多种原因的:async/await 状态机的开销,以及任务完成以使其线程进入请求上下文时的额外工作。除此之外,Win32 API 层仍然针对同步调用进行了大量优化(预计这将在未来十年左右逐渐改变)。

    那么,为什么要使用异步处理程序呢?

    出于可扩展性的原因。

    考虑一个 ASP.NET 服务器,它服务于多个请求 - 数百或数千个请求,而不是单个请求。在那种情况下,ASP.NET 将非常感谢在其请求处理期间返回给它的线程。它可以立即使用该线程来处理其他请求。异步请求允许 ASP.NET 用更少的线程处理更多的请求。

    当然,这是假设您的后端可以扩展。如果每个请求都必须访问单个 SQL Server,那么您的可伸缩性瓶颈可能是您的数据库,而不是您的 Web 服务器。

    但是,如果您的情况需要,异步代码可以极大地提高您的 Web 服务器可扩展性。

    有关更多信息,请参阅我在async ASP.NET 上的文章。

    【讨论】:

    • 这句话“以不需要线程的方式执行其操作..”是什么意思,如果没有其他线程,那么它如何在不使用主线程的情况下执行该操作?
    • @HamidBahmanabady:我有一个long blog post on that subject
    • for scalability reasons直接击中头部
    【解决方案3】:

    异步等待并不是某些人认为的灵丹妙药,在您的示例中也不需要。如果您在收到等待操作的结果后正在处理它,那么您将能够返回一个任务并继续调用线程。您不必等待其余的操作完成。删除上面代码中的 async/await 是正确的。

    在没有看到调用代码的情况下回答问题是不可能的,因为这取决于上下文试图对响应做什么。你得到的不仅仅是一个任务,而是一个在完成后将继续的方法上下文中的任务。请参阅 http://codeblog.jonskeet.uk/category/eduasync/ 以获取有关 async/await 内部工作原理的更多信息。

    最后,我会质疑您的时间安排,就像对数据库的 Ajax 请求一样,然后返回其他可能延迟更大的区域,例如 HTTP 请求和响应以及数据库连接本身。我假设您正在使用 ORM,仅此一项就会导致开销。我想知道问题是否在于异步/等待。

    【讨论】:

      猜你喜欢
      • 2019-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      • 2010-10-25
      • 2018-09-12
      相关资源
      最近更新 更多