【发布时间】:2020-04-08 14:32:53
【问题描述】:
为什么下面的代码在.Net4.8中会导致StackOverflowException,只有17个深度的递归?然而,这在 NetCore 3.1 中不会发生(我可以将计数设置为 10_000,它仍然有效)
class Program
{
static async Task Main(string[] args)
{
try
{
await TestAsync(17);
}
catch(Exception e)
{
Console.WriteLine("Exception caught: " + e);
}
}
static async Task TestAsync(int count)
{
await Task.Run(() =>
{
if (count <= 0)
throw new Exception("ex");
});
Console.WriteLine(count);
await TestAsync2(count);
}
static async Task TestAsync2(int count) => await TestAsync3(count);
static async Task TestAsync3(int count) => await TestAsync4(count);
static async Task TestAsync4(int count) => await TestAsync5(count);
static async Task TestAsync5(int count) => await TestAsync6(count);
static async Task TestAsync6(int count) => await TestAsync(count - 1);
}
这是 .Net 4.8 中的已知错误吗?我会在这样的函数中排除超过 17 级的递归......这是否实际上意味着不建议使用 async/await 编写递归?
更新:简化版
class Program
{
// needs to be compiled as AnyCpu Prefer 64-bit
static async Task Main(string[] args)
{
try
{
await TestAsync(97); // 96 still works
}
catch(Exception e)
{
Console.WriteLine("Exception caught: " + e);
}
}
static async Task TestAsync(int count)
{
await Task.Run(() =>
{
if (count <= 0)
throw new Exception("ex");
});
Console.WriteLine(count);
await TestAsync(count-1);
}
}
只有在选择 Any Cpu 并选择 32 位禁用 时才会如此快速,但在多个 .net 版本的多台机器(Windows 1903 和 1909)上可重现(.Net 4.7.2 和 .Net 4.8)
【问题讨论】:
-
count < 0时抛出。但是在TestAsync6中,您使用count-1调用TestAsync。不管你是从 17 还是 2 开始,迟早你都会用-1调用它,然后得到异常。我会说这是意料之中的。 -
嗯,是的,当
count <= 0时它会抛出,当用2调用它时这很好,而不是它会抛出,异常将被捕获并且一切都很好,但是当用@987654331 调用时@ 异常会被抛出,但又会导致堆栈溢出异常,这是我没想到的...... -
似乎存在一个相关问题,即 OP 在 .NET Framework 4.7.2 上遇到了与访问者模式相同的问题,但假设异常为什么是
StackOverflowException。看看:stackoverflow.com/questions/61102165/… -
我只是仔细检查了一遍。在 20000 的 Debug 和 Release 中运行在 4.7.2 下。作为一个魅力。
-
我能够在 .NET Framework 4.8 中使用
await TestAsync(235);重现它。但在这一点上,这是意料之中的。
标签: c# recursion async-await