【发布时间】:2012-11-28 07:00:54
【问题描述】:
我对@987654321@ 关键字的工作原理有一个脆弱的了解,我想稍微扩展一下对它的理解。
仍然让我头晕目眩的问题是递归的使用。这是一个例子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestingAwaitOverflow
{
class Program
{
static void Main(string[] args)
{
var task = TestAsync(0);
System.Threading.Thread.Sleep(100000);
}
static async Task TestAsync(int count)
{
Console.WriteLine(count);
await TestAsync(count + 1);
}
}
}
这个显然抛出了StackOverflowException。
我的理解是因为代码实际上是同步运行的,直到第一个异步操作,之后它返回一个 Task 对象,其中包含有关异步操作的信息。在这种情况下,没有异步操作,因此它只是在它最终会返回一个Task 的虚假承诺下不断递归。
现在稍微改变一下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestingAwaitOverflow
{
class Program
{
static void Main(string[] args)
{
var task = TestAsync(0);
System.Threading.Thread.Sleep(100000);
}
static async Task TestAsync(int count)
{
await Task.Run(() => Console.WriteLine(count));
await TestAsync(count + 1);
}
}
}
这个不会抛出StackOverflowException。我可以 sortof 了解它为什么起作用,但我会称它为一种直觉(它可能涉及如何安排代码使用回调来避免构建堆栈,但我无法翻译那种直觉的解释)
所以我有两个问题:
- 第二批代码如何避免
StackOverflowException? - 第二批代码会不会浪费其他资源? (例如,它是否在堆上分配了大量的 Task 对象?)
谢谢!
【问题讨论】:
标签: c# recursion async-await