只是面对这个奇怪的情况,我想知道这种模式是否会对堆栈使用产生任何保证(即可靠或不可靠)。
注意:计数器只是“DoIt”功能中的一项假设工作。
class Program
{
static void Main(string[] args)
{
DoIt();
Console.ReadKey();
_flag = true;
}
private static bool _flag;
private static int _count;
private static async void DoIt()
{
await Task.Delay(1000);
_count++;
if (_flag) return;
DoIt();
}
}
“DoIt”任务应该永远调用自己,直到某些东西(即标志)中断递归。我的奇怪是堆栈是否填满,因为它是针对“异步”调用,不应该停止调用者。
主要问题是:在某些情况下我可能会遇到StackOverflow异常,还是我保证不会出现这种情况?
如果我也删除延迟怎么办?
至于我,模式应该一直是安全的(几乎),但老实说,我不会解释如何保证它(至少不分析后面的IL代码)。只是怀疑当循环非常紧密,以便异步调用比整个函数本身“慢”。
答案 0 :(得分:4)
不,你最终会在很多任务上安排很多延续,而不是深层堆叠...至少在初始调用中。
请注意,这只是 ,因为您正在使用
await Task.Delay(1000);
......可以合理地预期永远不会返回已经完成的任务。如果你有类似的东西:
var value = await cache.GetAsync(key);
它可能很容易返回已完成的任务,那么你最终可能会得到一个非常深的堆栈。
您需要记住的是,只有在遇到未完成的第一个await
时,该呼叫才会同步。
如果我也删除延迟怎么办?
然后你有效地拥有一个递归调用自身的同步方法,除非标志很快被设置为 ,否则最终会出现堆栈溢出。
请注意,即使你没有在当前代码中获得堆栈溢出,你仍然每秒安排一个新任务,直到设置了标志,这是不理想的 - 它远非糟糕,因为任务无论如何都会快速消亡,但如果可能的话,我仍会使用循环。
一个潜在的问题是我相信“逻辑”堆栈仍然被捕获......随着你的进展,这将变得越来越大。这可能只是在调试的情况下 - 我不是它的专家。