异步方法如何使用堆栈?

时间:2013-12-08 20:00:19

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

我刚开始使用.NET异步编程,每个人都说它对服务器端代码更好,因为如果我使用异步keywork,ASP.NET将不会为每个请求创建线程,并将为所有异步代码重用相同的线程。

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

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

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

3 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:5)

考虑堆栈的用途:

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

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

3)激活当前方法后要运行的代码。

异步方法仅将堆栈用于第一个。 (在某些情况下,甚至可能必须将其中一些临时值移到堆上。)由于异步方法的变量可能比当前方法的激活持续时间更长,因此必须将它们移动到堆上。异步方法的重点是它将其连续存储在别处,它不使用堆栈作为延续的具体化。

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

答案 2 :(得分:0)

  

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

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

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

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