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

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

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

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

  • http 请求由线程池中的线程提供服务。
  • 当请求正在处理时,这个线程很忙,因为请求正在这个线程内处理。
  • 当请求处理完成时,线程返回线程池,服务器发送响应。

  • 这种描述的行为正确吗?

    当我在 ASP.NET MVC Controller 中启动新任务时,究竟会发生什么?
    public ActionResult Index()
    {
        var task1 = Task.Factory.StartNew(() => DoSomeHeavyWork());
        return View();
    }
    
    private static async Task DoSomeHeavyWork()
    {
        await Task.Delay(5000);
    }
    
  • Controller Action 开始在处理当前请求的线程内执行 - T1。
  • 线程池为task1分配另一个线程(T2)。
  • task1 在 T2 内“立即”启动。
  • 查看结果“立即”返回。
  • ASP.NET 做一些工作,服务器发送响应,T1 返回线程池,T2 还活着。
  • 在 DoSomeHeavyWork 完成一段时间后,T2 线程将返回到线程池。

  • 这是正确的吗 ?

    现在让我们看看异步操作
    public async Task<ActionResult> Index()
    {
        await DoSomeHeavyWork();
        return View();
    }
    

    ,我了解与以前的代码示例的区别,但不了解过程,在此示例中,行为如下:
  • Action 开始在处理当前请求的线程内执行 - T1。
  • DoSomeHeavyWork “立即”返回一个任务,我们也称它为“task1”。
  • T1 返回线程池。
  • DoSomeHeavyWork 完成后,Index 操作继续执行。
  • 索引操作执行后,服务器将发送响应。

  • 请解释第 2 点和第 5 点之间发生的情况,问题是:
  • DoSomeHeavyWork 是在 task1 内处理还是在哪里(“等待”的地方)处理?我认为这是一个关键问题。
  • 等待后哪个线程将继续处理请求-线程池中的任何新线程,对吗?
  • request 产生从线程池分配的线程,但是在 DoSomeHeavyWorkAsync 完成之前不会发送响应,并且此方法在哪个线程中执行都没有关系。换句话说,根据 请求和 具体任务(DoSomeHeavyWork)使用异步没有任何好处。这是正确的吗 ?
  • 如果前面的语句是正确的,那么我不明白异步如何提高具有相同 的多个请求的性能单任务。我会尽力解释。假设线程池有 50 个线程可用于处理请求。单个请求至少应该由线程池中的一个线程处理,如果该请求启动了另一个线程,那么它们都将从线程池中取出,例如request 需要一个线程来处理自己,并行启动 5 个不同的任务并等待所有任务,线程池将有 50 - 1 - 5 = 44 个空闲线程来处理传入的请求 - 所以这是一种并行性,我们可以提高单个任务的性能请求,但我们减少了可以处理的请求数量。因此,根据 ASP.NET 中的请求处理,我认为只有以某种方式启动 IO 完成线程的任务才能实现异步(TAP)的目标。但是在这种情况下 IO 完成线程如何回调线程池线程呢?
  • 最佳答案

    Is this described behaviour right ?



    是的。

    Is it correct ?



    是的。

    is the DoSomeHeavyWork processed inside task1 or where (where it is "awaited") ? I think this a key question.



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

    which thread will continue to process the request after await?



    因为我们讨论的是 ASP.NET,这将是一个任意线程池线程,HttpContext编码到它上面。如果这是 WinForms 或 WPF 应用程序,您将在 await 之后再次访问 UI 线程。 ,假设您不使用 ConfigureAwait(false) .

    request produces thread allocating from the thread pool, but response will not be sent until the DoSomeHeavyWorkAsync finished and it doesn't matter in which thread this method executes. In other words, according to single request and single concrete task (DoSomeHeavyWork) there is no benefits of using async. Is it correct ?



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

    But how IO completion thread calls back thread pool thread in this case ?



    您必须将并行性和并发性分开。如果您需要计算能力来并行执行 CPU 密集型工作,那么异步不是实现它的工具。另一方面,如果您有大量并发的 IO 绑定(bind)操作,例如为 CRUD 操作访问数据库,您可以通过在执行 IO 操作时释放线程来从使用异步中受益。这是异步的主要关键点。

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

    关于ASP.NET 和异步 - 它是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30391687/

    相关文章:

    c# - 当我在 mvc 的 ModelState 中使用 Ajax 更新数据库时

    javascript - Appium代码生成 "SyntaxError: await is only valid in async function"

    sockets - perl6 IO::Socket::Async 服务器因异常而终止:连接被对等方重置

    c# - 异步方法不能返回任何具有可访问的 GetAwaiter 方法的类型

    javascript - 设置下拉列表的选定值,其中使用 Jquery 动态附加下拉列表的选项

    c# - asp.Net MVC 如何为图表中的每个条形设置颜色?

    asp.net - Paypal 返回网址

    javascript - Gridview 模板 Javascript 数据绑定(bind)

    asp.net - AntiForgeryToken 是否需要 session 状态?

    javascript - AJAX 将带有数据和多个图像的表单发送到 asp.net mvc 操作