是否存在技术上的原因,C#不发布“ tail”。 CIL指令? [重复]

可能重复:
.net / C#为什么不消除尾部递归?

采用以下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)。为解决此问题,某些语言会执行此操作

我的理解是,.NET 4 JIT的64位实现现在可以执行TCO并避免了TCO,这称为递归调用消除或拖尾调用优化(TCO)。 上面的CIL这样的代码溢出了,但是32位的JIT却没有,Mono也没有。有趣的是,JIT(在时间和资源压力下)执行了TCO,而C#编译器却没有。 问题是为什么C#编译器本身不更了解TCO?

有一条CIL指令告诉JIT执行TCO。例如,C#co mpiler可能会生成以下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)上也将运行到完成。 魔术在尾巴中。 CIL指令。 像F#这样的编译器会自动生成包含该指令的CIL。

所以我的问题是,C#编译器不执行此操作有技术上的原因吗?

我知道它在历史上可能只是不值得。 像 Counter()这样的代码在惯用的C#和/或.NET框架中并不常见。 您可以轻松地将C#的TCO视为不必要或过早的优化。

随着LINQ和其他功能的引入,似乎C#和C#开发人员都朝着更多的功能方向发展。 因此,如果使用递归不是一件不安全的事情,那将是很好的。 但是我的问题确实是技术性更高的问题。

遗漏了一些使TCO这样的东西对C#来说不是一个好主意(或冒险)。 还是有什么事情使正确做事变得特别棘手? 这确实是我希望了解的。 有任何见解吗?

编辑:感谢您提供的宝贵信息。 我只是想明确一点,我不是在批评缺乏甚至不要求此功能。 我对围绕优先级排序的合理性并不超级感兴趣。 我的好奇心是我可能无法理解或理解的障碍,这使这件事变得困难,危险或不受欢迎。

也许不同的背景将有助于使谈话的重点...

让我说我要实现 我在CLR上自己的类似C#的语言。 我为什么不(机会成本除外)包括自动透明地发出“尾巴”。 说明在适当的地方? 在非常类似于C#的语言中支持该功能时,我会遇到什么挑战或遇到什么限制。

再次(并提前)感谢您的答复。

26
задан Community 23 May 2017 в 10:28
поделиться