tl;dr;
在C#中,你能保证一个懒惰的迭代器函数只调用它自己,并且有一个有效的递归退出条件不会导致堆栈溢出吗?
详细问题:
我知道通常你不能保证C#编译器(或JIT)生成的尾部调用优化(TCO)指令,所以虽然你可能会得到TCO,但没有保证。
鉴于对总拥有成本的认识,我想知道惰性迭代器函数(使用yield return等)是否因为其作为协程的本质而被占用堆栈空间?我对协程的直觉是,因为它们的可重入性,每个尾部调用在默认情况下都是优化的,因为从父帧跳出并进入下一个函数的能力看起来很自然,而不是创建一个新的帧。
这是在C#中的行为,还是C#迭代器函数的递归调用从当前框架创建新框架,而不是弹出到父框架并使用新参数重新进入?
示例:
public static IEnumerable<IEnumerable<T>> GeneratePermutations<T>(this IEnumerable<T> choices, int numberToChoose)
{
if (numberToChoose == 1)
{
foreach (var choice in choices)
yield return new T[] { choice };
yield break;
}
var subPermutations = choices.SelectMany(choice =>
choices.Where(elem => !EqualityComparer<T>.Default.Equals(elem, choice))
.GeneratePermutations(numberToChoose - 1)
.Select(permutation => (new T[] { choice }).Concat(permutation)));
foreach (var perm in subPermutations)
yield return perm;
}我的直觉是基于上面的例子subPermutations是一个简单的堆计算,似乎在调用迭代它时,它可以知道它是一个堆计算(它是函数sig的一部分,它是一个迭代器函数),因此立即跳出它的当前帧并将堆计算扩展到一个新帧--在尝试递归调用之前不会消耗额外的堆栈空间。
这种直觉可能是完全没有根据的。
https://stackoverflow.com/questions/25315542
复制相似问题