这个问题已经在这里有了答案:
9年前关闭。
请使用以下C#代码:
using System;
namespace TailTest
{
class MainClass
{
public static void Main (string[] args)
{
Counter(0);
}
static void Counter(int i)
{
Console.WriteLine(i);
if (i < int.MaxValue) Counter(++i);
}
}
}
C#编译器(无论如何还是我的)都会将Counter方法编译为以下CIL:
.method private static hidebysig default void Counter (int32 i) cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call void class [mscorlib]System.Console::WriteLine(int32)
IL_0006: ldarg.0
IL_0007: ldc.i4 2147483647
IL_000c: bge IL_0019
IL_0011: ldarg.0
IL_0012: ldc.i4.1
IL_0013: add
IL_0014: call void class TailTest.MainClass::Counter(int32)
IL_0019: ret
}
上面的代码的问题是,它将导致堆栈溢出(在我的硬件上大约为i = 262000)。为了解决这个问题,某些语言执行了所谓的尾音消除或尾音优化(TCO)。本质上,它们将递归调用变成一个循环。
我的理解是.NET 4 JIT的64位实现现在可以执行TCO,并且可以避免上述CIL之类的代码溢出。但是,32位JIT不会。单声道似乎也没有。有趣的是,JIT(在时间和资源压力下)执行TCO,而C#编译器则不这样做。我的问题是,为什么C#编译器本身不更了解TCO?
有一条CIL指令告诉JIT执行TCO。例如,C#编译器可以代替生成以下CIL:
.method private static hidebysig default void Counter (int32 i) cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call void class [mscorlib]System.Console::WriteLine(int32)
IL_0006: ldarg.0
IL_0007: ldc.i4 2147483647
IL_000c: bge IL_001c
IL_0011: ldarg.0
IL_0012: ldc.i4.1
IL_0013: add
IL_0014: tail.
IL_0017: call void class TailTest.MainClass::Counter(int32)
IL_001c: ret
}
与原始代码不同,即使在32位JIT(.NET和Mono)上,该代码也不会溢出并且可以运行到完整状态。神奇之处在于
tail.
CIL指令。像F#这样的编译器会自动生成包含此指令的CIL。所以我的问题是,C#编译器不执行此操作有技术原因吗?
我知道,从历史上看,这也许不值得。在惯用的C#和/或.NET框架中,像
Counter()
这样的代码并不常见。您可以轻松地将C#的TCO视为不必要或过早的优化。随着LINQ等的引入,似乎C#和C#开发人员都朝着更多的功能方向发展。因此,如果使用递归不是一件不安全的事情,那将是很好的。但是我的问题确实是一个技术性更高的问题。
缺少使TCO这样的东西对C#来说不是一个好主意(或冒险)的东西。还是有什么事情使正确做事特别棘手?这确实是我希望了解的。有见识吗?
编辑:非常感谢您提供的信息。我只是想明确一点,我不是在批评缺少甚至不要求此功能。我对围绕优先级排序的合理性并不 super 感兴趣。我的好奇心是我可能无法理解或理解的哪些障碍使这件事变得困难,危险或令人讨厌。
也许不同的背景将有助于使谈话重点...
假设我要在CLR上实现自己的类似于C#的语言。我为什么不(机会成本除外)包括“尾部”的自动透明排放。说明在适当的地方?在非常类似于C#的语言中支持此功能时,我会遇到什么挑战或遇到什么限制。
再次(并提前)感谢您的答复。
最佳答案
检查以下链接
Why doesn't .NET/C# optimize for tail-call recursion?
/491463#491463
http://social.msdn.microsoft.com/Forums/en-US/netfxtoolsdev/thread/67b6d908-8811-430f-bc84-0081f4393336?StatusCode=1
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=166013&wa=wsignin1.0
以下声明是MS官方的(Luke Hoban Visual C#编译器程序管理器),并从最后一个链接复制而来
关于c# - C#不发出 “tail.” CIL指令是出于技术原因吗? [复制],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7096157/