【问题标题】:How do async methods use stack?异步方法如何使用堆栈?
【发布时间】:2013-12-25 20:04:46
【问题描述】:

我刚开始使用 .NET 异步编程,每个人都说它更适合服务器端代码,因为如果我使用异步密钥,ASP.NET 不会为每个请求创建线程,而是会为所有异步代码重用相同的线程.

因为每个线程都需要堆栈,并且可能有数百个线程,它可以节省大量内存,例如:

regular: 1500 threads x 2mb = 3000 mb
async:   20 threads x 2mb   =   40 mb

但这是否意味着异步代码在没有堆栈的情况下执行?或者它存储在哪里以及 .NET 如何使用它?

【问题讨论】:

  • 请注意,异步在所有方面都不是完全“对服务器更好”。权衡更复杂。

标签: c# asp.net .net async-await


【解决方案1】:

您创建的每个线程都会分配一个完整的堆栈,无论您在该线程上使用多少堆栈。
因此,创建更少的线程将节省内存。

当异步方法等待操作完成时,它会将其状态保存在 GC 管理的堆上的编译器生成的对象(如 lambda 表达式的闭包)中。

【讨论】:

    【解决方案2】:

    但这是否意味着异步代码在没有堆栈的情况下执行?

    这意味着async 代码正在等待 没有堆栈。例如,当您有这样的代码时:

    Uri url = CreateUrl(id);
    string result = await DownloadData(url);
    int result = ProcessData(result);
    

    然后CreateUrl()ProcessData() 在一个线程上正常执行并使用该线程的堆栈。但是在DownloadData() 等待下载完成期间,没有使用线程(假设DownloadData() 异步写入正确)。这对于 ASP.NET 应用程序(和类似应用程序)来说是一个很大的优势,因为这意味着线程只会在很短的时间内被阻塞,并且可以使用少量线程来处理大量请求。

    【讨论】:

      【解决方案3】:

      想想堆栈的用途:

      1) 执行单个语句和表达式期间所需的临时空间。当您说“a = b + c + d”时,“b + c”的结果必须先存储在某个位置,然后才能添加到 d。

      2) 存储已知生命周期等于或小于当前方法激活的其他变量。

      3) 当前方法激活完成后运行什么代码。

      异步方法仅在第一个使用堆栈。 (即使那样,在某些情况下也可能必须将其中一些临时变量移到堆上。)由于异步方法的变量可能比方法的当前激活持续时间更长,因此必须将它们移到堆上。而异步方法的全部意义在于它将其延续存储在别处,它不使用堆栈作为延续的具体化。

      因此,异步方法很少使用堆栈。相反,它们使用堆内存来存储激活和继续信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-03
        • 1970-01-01
        • 1970-01-01
        • 2016-05-25
        • 1970-01-01
        • 1970-01-01
        • 2019-11-05
        • 2014-12-02
        相关资源
        最近更新 更多