ASP.NET和异步 - 它是如何工作的?

时间:2015-05-22 08:18:51

标签: asp.net asp.net-mvc async-await task-parallel-library

我知道这是一个常见的问题,但我读过一篇文章并感到困惑。现在我认为最好不要阅读它们。)。

那么,ASP.NET如何工作(仅关于线程):

  1. http请求由线程池中的线程提供。
  2. 当请求正在处理时,这个线程正忙,因为请求正在这个线程中处理。
  3. 当请求处理完成时,线程返回线程池,服务器发送响应。
  4. 这描述的行为是对的吗?

    当我在ASP.NET MVC控制器中启动新任务时会发生什么?

    public ActionResult Index()
    {
        var task1 = Task.Factory.StartNew(() => DoSomeHeavyWork());
        return View();
    }
    
    private static async Task DoSomeHeavyWork()
    {
        await Task.Delay(5000);
    }
    
    1. 控制器操作开始在处理当前请求的线程内执行 - T1。
    2. 线程池为task1分配另一个线程(T2)。
    3. task1启动"立即"在T2内。
    4. 查看结果"立即"。
    5. ASP.NET做一些工作,服务器发送响应,T1返回线程池,T2仍然活着。
    6. 在DoSomeHeavyWork完成一段时间后,T2线程将返回到线程池。
    7. 这是对的吗?

      现在让我们看一下异步动作

      public async Task<ActionResult> Index()
      {
          await DoSomeHeavyWork();
          return View();
      }
      

      ,我理解与以前代码示例的区别,但不了解该过程,在此示例中,行为如下:

      1. 操作开始执行处理当前请求的内部线程 - T1。
      2. DoSomeHeavyWork&#34;立即&#34;返回一个任务,让我们称之为&#34; task1&#34;太
      3. T1返回线程池。
      4. 在DoSomeHeavyWork完成后,Index操作继续执行。
      5. 执行索引操作后,服务器将发送响应。
      6. 请解释第2点和第5点之间发生的事情,问题是:

        1. 是在task1内部处理的DoSomeHeavyWork,或者在哪里(等待#34;等待#34;)?我认为这是一个关键问题。
        2. 在等待之后哪个线程将继续处理请求 - 来自线程池的任何新线程,对吧?
        3. 请求从线程池生成线程分配,但在DoSomeHeavyWorkAsync完成之前不会发送响应,并且此方法执行的线程无关紧要。换句话说,根据单个请求和单个具体任务(DoSomeHeavyWork),使用异步没有任何好处。这是对的吗?
        4. 如果之前的陈述是正确的,那么我就不会理解异步如何通过相同的单个任务来提高多个请求的性能。我试着解释一下。让我们假设线程池有50个线程可用于处理请求。单个请求应至少由来自线程池的一个单个线程处理,如果请求启动另一个线程,则所有这些线程将从线程池中获取,例如,请求需要一个线程来处理自己,并行启动5个不同的任务并等待所有这些任务,线程池将有50 - 1 - 5 = 44个空闲线程来处理传入请求 - 所以这是一个并行性,我们可以提高单个性能请求,但我们减少了可以处理的请求数。因此,根据ASP.NET中的请求处理,我认为只有以某种方式启动IO完成线程的任务才能实现异步(TAP)的目标。但在这种情况下,IO完成线程如何回调线程池线程?

1 个答案:

答案 0 :(得分:6)

  

这描述的行为是对的吗?

  

这是对的吗?

  

是在task1或其中(在何处)处理的DoSomeHeavyWork   &#34;等待&#34;)?我认为这是一个关键问题。

从当前代码中,DoSomeHeavyWork将异步等待Task.Delay完成。是的,这将发生在线程池分配的同一个线程上,它不会旋转任何新线程。但是,并不能保证它将是相同的线程

  

在等待之后哪个线程将继续处理请求?

因为我们正在讨论ASP.NET,所以它将是一个任意的线程池线程,HttpContext封送在它上面。如果这是WinForms或WPF应用,那么您将在await之后再次访问UI线程,因为您不会使用ConfigureAwait(false)

  

请求生成从线程池分配的线程,但响应   在DoSomeHeavyWorkAsync完成之前不会发送它   这个方法在哪个线程中执行并不重要。换一种说法,   根据单一要求和单一具体任务(DoSomeHeavyWork)   使用异步没有任何好处。这是对的吗?

在这种特殊情况下,您不会看到异步的好处。当你有并发请求命中服务器时,异步会闪耀,而且很多都在进行IO绑定工作。例如,当您在访问数据库时使用异步时,您可以在查询执行的时间内释放线程池线程,从而允许同一个线程同时处理更多请求。

  

但IO完成线程如何在此回调线程池线程   案件?

您必须将并行性和并发性分开。如果你需要计算能力来并行执行CPU绑定工作,async就不是实现它的工具。另一方面,如果你有很多并发 IO绑定操作,比如命中数据库进行CRUD操作,你可以通过释放线程来使用async,而IO操作则是执行。这是异步的主要关键点。

线程池具有专用的IO完成线程池以及工作线程,您可以通过调用ThreadPool.GetAvailableThreads来查看它们。当您使用IO绑定操作时,检索回调的线程通常是 IO完成线程,而不是工作线程。他们都有不同的游泳池。