为什么这里没有发生尾调用优化?
Why is tail call optimization not occurring here?
我们正在使用递归来查找因子并收到 Whosebug 异常。我们读到 the C# compiler on x64 computers performs tail call optimizations:
JIT definitely does tailcals when running optimized code and not debugging.
运行 dotnet --configuration release
在我们的程序中走到了这一步:
...
7214 is a factor of 1234567890
7606 is a factor of 1234567890
10821 is a factor of 1234567890
11409 is a factor of 1234567890
Process is terminated due to WhosebugException.
为什么没有发生尾调用优化?
class Program
{
static void Main(string[] args)
{
const long firstCandidate = 1;
WriteAllFactors(1234567890, firstCandidate);
}
private static void WriteAllFactors(long number, long candidate)
{
if (number % candidate == 0)
{
System.Console.WriteLine($"{candidate} is a factor of {number}");
}
candidate = candidate + 1;
if(candidate > number / 2)
{
return;
}
WriteAllFactors(number, candidate);
}
}
VSadov 在他的回复中提供了明确的原因:
Generally JIT emits tail calls when it finds that profitable.
此外,他接着说:
This is a part that is not expressible in C#. Unlike inlining, which
can be forced via attributes, tailcalling cannot be currently forced.
If one needs to write the code like emitted by EmitMethodCall, he
cannot use C#.
所以答案是虽然尾调用肯定可用和使用,但无法预测它们何时会被使用或强制它们在 C# 中使用。
我们正在使用递归来查找因子并收到 Whosebug 异常。我们读到 the C# compiler on x64 computers performs tail call optimizations:
JIT definitely does tailcals when running optimized code and not debugging.
运行 dotnet --configuration release
在我们的程序中走到了这一步:
...
7214 is a factor of 1234567890
7606 is a factor of 1234567890
10821 is a factor of 1234567890
11409 is a factor of 1234567890
Process is terminated due to WhosebugException.
为什么没有发生尾调用优化?
class Program
{
static void Main(string[] args)
{
const long firstCandidate = 1;
WriteAllFactors(1234567890, firstCandidate);
}
private static void WriteAllFactors(long number, long candidate)
{
if (number % candidate == 0)
{
System.Console.WriteLine($"{candidate} is a factor of {number}");
}
candidate = candidate + 1;
if(candidate > number / 2)
{
return;
}
WriteAllFactors(number, candidate);
}
}
VSadov 在他的回复中提供了明确的原因:
Generally JIT emits tail calls when it finds that profitable.
此外,他接着说:
This is a part that is not expressible in C#. Unlike inlining, which can be forced via attributes, tailcalling cannot be currently forced. If one needs to write the code like emitted by EmitMethodCall, he cannot use C#.
所以答案是虽然尾调用肯定可用和使用,但无法预测它们何时会被使用或强制它们在 C# 中使用。