我刚开始使用.NET异步编程,每个人都说它对服务器端代码更好,因为如果我使用异步keywork,ASP.NET将不会为每个请求创建线程,并将为所有异步代码重用相同的线程。
因为每个线程都需要堆栈,并且可能有数百个线程,所以它有机会节省大量内存,例如:
regular: 1500 threads x 2mb = 3000 mb
async: 20 threads x 2mb = 40 mb
但这是否意味着异步代码在没有堆栈的情况下执行?或者它存储在哪里以及.NET如何使用它?
答案 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应用程序(以及类似的)来说是一个很大的优势,因为它意味着线程仅在很短的时间内被阻止,并且可以使用少量线程来处理大量请求。