首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么.NET/C#不能优化尾调用递归?

在云计算领域,尾调用递归是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用递归不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因为.NET/C#的运行时不支持尾调用优化。

在.NET/C#中,尾调用优化是一种优化技术,它可以减少栈空间的使用,从而提高程序的性能。然而,在.NET/C#中,尾调用优化不能被优化,这是因

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

递归调用优化

之前分享过递归,其中有一个优化就是调用。 先明确调用的概念: 调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是return调用另一个函数。...注意,并不是所有的函数都能调用优化,要看你这个函数需不需要使用某些上个函数的变量或者什么的。...调用优化其实很大一部分就是递归函数在使用,因为递归函数调用的时候非常耗费内存,可能需要保存成百上千调用栈,很容易内存溢出。如果是递归就只有一个调用栈,能把复杂度O(n)的变成O(1)。...,然后使用蹦床函数实现调用优化。...而ES6对调用有什么优化?就是函数默认值,在一些场景下,比如阶乘的递归,采用默认值实现递归优化。 (完)

68810

探索c#递归编译器优化

在阶乘过程中,堆栈需要保存每次(RecFact)调用的返回地址及当时所有的局部变量状态,期间堆栈空间是无法释放的(即容易出现溢出)。 为了优化堆栈占用问题,从而提出递归优化的办法。...由于递归期间,堆栈是可以释放/再利用的,也就解决递归过深而引起的溢出问题,这也是递归的优势所在。 编译器优化 递归优化,看起来是蛮美好的,但在net中却有点乱糟糟的感觉。...NetC#语言中是JIT编译成汇编时进行优化的。 Net在IL上,有个特殊指令tail去实现递归优化的(F#中)。...我们执行 TailRecursion(0)(x==1000000) 得出如下结论: C#/64位/Release是有JIT编译器进行尾递归优化的(非C#编译器优化)。 ?...但在函数式编程思想当中,递归/递归使用则是主流用法,就像在C#使用循环一样。

1.4K70
  • 2020-1-6-什么是递归

    递归算法想必大家都已经很熟悉了。递归算法虽然简单,但是容易导致一些性能问题,于是就有了递归这种优化算法。 ---- 首先我们先看看递归算法的性能问题是在哪里?...此时程序会将当前上下文压栈,计算出下一个foo的值,然后再出栈和x进行相乘 所以对于foo(3)的调用,整个栈的情况是这样的 那么递归呢?...它是指函数的最后一个位置(或者动作)是调用自身 我们把上面的方法改一下递归 //C#递归实现 int Foo(int x, int result=1) { if(x==1) {...目前我知道的是python是支持的,探索c#递归编译器优化 - 蘑菇先生 - 博客园文章中表示64位release下会进行尾递归优化 ---- 参考文档: 调用 - 维基百科,自由的百科全书 探索...c#递归编译器优化 - 蘑菇先生 - 博客园 ---- 本文会经常更新,请阅读原文: https://xinyuehtx.github.io/post/%E4%BB%80%E4%B9%88%E6%98%

    27820

    探索c#递归APS和CPS

    接上篇探索c#递归编译器优化 累加器传递模式(APS) CPS函数 CPS变换 CPS递归 总结 累加器传递模式(Accumulator passing style) 递归优化在于使堆栈可以不用保存上一次的返回地址.../状态值,从而把递归函数当成一个普通的函数调用。...递归实际上是依赖上次的值,去求下次的值。 如果我们能把上次的值保存起来,在下次调用时传入,而不直接引用函数返回的值。 从而使堆栈释放,也就达到了递归优化的目的。...调用如下: var ac = Accumulate(1, 20); 使用Lambda表达式实现递归阶乘: static int AccumulateByLambda(int x) {...其实我们还可以用返回函数的C#语法,构造嵌套方式,把函数的调用变成调用链times3(3)(5)。 这种方式在数学上或函数式编程中是比较直观的,正常的,但在指令式语言c#中却不是那么直观。

    1.2K70

    Python中的递归

    递归 递归的原理:当编译器检测到一个函数调用递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。...---- 换一种说法,递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。...这样,编译器或者解释器就可以把递归优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。...递归优化 通过实现一个 tail_call_optimized 装饰器,来优化递归。 #!..._getframe().f_back # 调用者的帧 ---- tail_call_optimized实现递归优化的原理: 当递归函数被该装饰器修饰后, 递归调用在装饰器while循环内部进行, 每当产生新的递归调用栈帧时

    1.3K30

    在Java中谈递归--递归和垃圾回收的比较(转载)

    一个误区,不是因为调用自身而开销巨大,而是嵌套加上轻易就能无数次调用,使得递归可以很容易开销巨大 既然会导致内存溢出泄露如此,那肯定要想办法了,方法很简单,那就是递归优化 二、递归优化 递归优化是利用上面的第一个特点...“调用同一个方法”来进行优化递归优化其实包括两个东西:1)递归的形式;2)编译器对递归优化 递归的形式 递归其实只是一种对递归的特殊写法,这种写法原本并不会带来跟递归不一样的影响,它只是写法不一样而已...比如如果有返回值的,你不能:乘个常数 return 3f(n);乘个n return n*f(n);甚至是 f(n)+f(n-1) 另外,使用return的递归还跟函数式编程有一点关系 编译器对递归优化...,不仅不用释放上一个,连下一个新的都不用开,效率非常高(有人做实验,这个比递推比迭代都要效率高) 为什么写成递归的形式,编译器就能优化了?...那为什么呢,我看到有的说法是:JAVA编写组不实现递归优化是觉得麻烦又没有太大的必要,就懒得实现了(原话是:在日程表上,但是非常靠后),官方的建议是不使用递归,而是使用while循环,迭代,递推 转载

    1.4K50

    递归的后续探究

    这也就是上文提到调用栈溢出的直接原因,各大浏览器(除了safari)根本就没部署调用优化,直接在浏览器上的控制台上调试递归的代码当然还是会出现栈溢出的问题。 施工中......那么为什么V8引擎都已经实现了调用优化,但是默认不开启呢? 3 调用优化默认关闭 V8 blog里有这么一篇文章《ES6, ES7 and beyond》给了我们对应的解释。...3.1 隐式优化问题 首先,由于引擎消除递归是隐式的,函数是否符合调用而被消除了递归很难被程序员自己辨别。...而且你也不能保证调试出来的结果是不是因为运气好而表现出了正常的结果。这也就是隐式优化所带来的一大问题。...下使用递归写法的方法依旧出现调用栈溢出的原因在于: 直接原因: 各大浏览器(除了safari)根本就没部署调用优化 根本原因: 调用优化依旧有隐式优化调用栈丢失的问题 参考资料 朋友你听说过递归

    1K100

    递归的后续探究

    这也就是上文提到调用栈溢出的直接原因,各大浏览器(除了safari)根本就没部署调用优化,直接在浏览器上的控制台上调试递归的代码当然还是会出现栈溢出的问题。 ---- 施工中......那么为什么V8引擎都已经实现了调用优化,但是默认不开启呢? 3 调用优化默认关闭 V8 blog里有这么一篇文章《ES6, ES7 and beyond》给了我们对应的解释。...3.1 隐式优化问题 首先,由于引擎消除递归是隐式的,函数是否符合调用而被消除了递归很难被程序员自己辨别。...而且你也不能保证调试出来的结果是不是因为运气好而表现出了正常的结果。这也就是隐式优化所带来的一大问题。...下使用递归写法的方法依旧出现调用栈溢出的原因在于: 直接原因: 各大浏览器(除了safari)根本就没部署调用优化 根本原因: 调用优化依旧有隐式优化调用栈丢失的问题 参考资料 朋友你听说过递归

    1.5K22

    JavaScript 中的调用优化

    为什么调用重要呢,原因是它不会在调用栈上增加新的堆栈帧,而是直接更新调用栈,调用栈所占空间始终是常量,节省了内存,避免了爆栈的可能性。...而递归之所以可以优化,是因为每次递归调用的时候,当前作用域中的局部变量都没有用了,不需要层层增加调用栈再在最后层层回收,当前的调用帧可以直接丢弃了,这才是调用可以优化的原因。...由于递归调用的一种特殊形式,相对简单一些,在 ES6 没有开启调用优化的时候,我们可以手动为递归做一些优化。...递归优化 改写为循环 之所以需要优化,是因为调用栈过多,那么只要避免了函数内部的递归调用就可以解决掉这个问题,其中一个方法是用循环代替递归。...逻辑运算符(|| 与 &&) 首先是 || 运算符: const a = () => f() || g() 这里 f 函数不在递归位置上,而 g 函数在递归位置上,为什么,把函数改写一下就清楚了:

    1.1K10

    .net面试题常见有答案(java中级开发面试题)

    //1.递归算法求30位数字 public static int MyFoun_04(int n) { //一组数值排序如下1、1、2、3、5、8、13、21、34....用递归求30位数字...程序是如何编译的 解答: .NET的程序是由多种语言编译的,如C#、VB、C++、J#等,但是最后都会由各自的编译器编译为一致的中间语言(IL)。....NET Framework由【公共语言】运行时(CLR)和基类库(BCL)组成,前者提供运行库环境,而后者提供丰富的类库,适合全部.NET编程语言调用。...基类库不仅封装了各种类型,而且还支持很多服务 .NET程序的中间语言(IL)也被称为托管代码,优点: 1. 平台无关性。 2. JIT性能优化。 3. 语言互操作性。...Continue: 也是终止当前的循环过程,但他并不跳出循环,而是继续往下判断循环条件执行语句.他只能结束循环中的一次过程,但不能终止循环继续进行 Return: 语句可被用来使 正在执行分支程序返回到调用它方法

    66830

    如何优化调用

    需要了解如何优化递归的话,我们需要从最开始讲起。 什么是调用 什么是递归 如何优化递归 调用 从字面理解,自然而言就是在函数的尾部返回一个函数的调用,通常来说,指的是函数执行的最后一步。...const fn = () => f1() || f2() // 这里的话, f2函数有可能是调用,f1不可能是调用 为什么f1函数不是呢,我们看这个函数的等价形式?...---- 说到这里,为什么要说调用呢?我们事先想一想传统的递归,典型的就是首先执行递归调用,然后根据这个递归的返回值并结算结果,那么传统的递归缺点有哪些呢? 效率低,占内存。...手动优化 既然我们知道了,很多浏览器对于递归优化支持的浏览器并不多,那你会好奇,当我们使用递归进行优化的时候,依然出现栈溢出的错误,那么我们如何解决呢??...对于递归而言,我们需要了解优化它的原理,如果有必要的话,将递归的形式写成迭代的形式,通过迭代方式,降低重复值的计算,当然了,这个过程,有时候是比较难的,值得我们去思考。 参考 调用递归

    89130

    大家都知道递归递归呢?什么又是递归优化

    为什么会有“栈溢出”呢?因为函数调用的过程,都要借助“栈”这种存储结构来保存运行时的一些状态,比如函数调用过程中的变量拷贝,函数调用的地址等等。...从“”字可看出来即若函数在尾巴的地方递归调用自己。...为什么呢?因为这种写法,本质上还是有多层的函数嵌套调用,中间仍然有压栈、出栈等占用了存储空间(只不过能比前面的方法会省部分空间)。...默认启用递归优化正常计算结果,禁用递归优化则“StackOverflow”。 我们来看看生成的字节码有什么不同。 ? 包含递归优化的字节码,直接 goto 循环。 ?...禁用递归优化的字节码,方法调用。 从上面可以看出,递归优化后,变成循环了(前面的 C++ 类似)。 好了,递归咱们就了解到这里。

    1.5K30

    面试官:说一说递归如何优化-递归优化

    编者荐语:本文旨在帮助大家掌握递归的性能优化方案——递归优化,以及如何对下列函数用递归进行优化?...如果所有函数都是调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是"调用优化"的意义。 三、递归 函数调用自身,称为递归。如果调用自身,就称为递归。...这样做的缺点就是不太直观,第一眼很难看出来,为什么计算5的阶乘,需要传入两个参数5和1? 两个方法可以解决这个问题。 方法一:是在递归函数之外,再提供一个正常形式的函数。...总结一下,递归本质上是一种循环操作。纯粹的函数式编程语言没有循环操作命令,所有的循环都用递归实现,这就是为什么递归对这些语言极其重要。...对于其他支持"调用优化"的语言(比如Lua,ES6),只需要知道循环可以用递归代替,而一旦使用递归,就最好使用递归

    3.7K22

    调用

    这样的缺点是不太直观,第一眼很难看出来,为什么计算 5 的阶乘需要传入两个参数 5 和 1? 有两个方法可以解决这个问题。方法一是在递归函数之外再提供一个正常形式的函数。...总结以下,递归本质是一种循环操作。纯粹的函数式编程没有循环操作命令,所有循环都用递归实现,这就是为什么递归对于这些语言极其重要。...对于其他支持”调用优化“的语言(比如 Lua、ES6),只需要知道循环可以用递归代替,而一旦使用递归,就最好使用递归。 严格模式 ES6 的调用优化只在严格模式下开启,正常模式下是无效的。...递归优化只在严格模式下生效,那么在正常模式下, 或者在那些不支持该功能的环境中,有没有办法啊使用递归优化呢?...回答是肯定的——自己实现递归优化。 原理非常简单。递归之所以需要优化,愿意是调用栈太多造成溢出,那么只要减少调用栈就不会溢出了。怎么做可以减少调用栈呢?答案是采用”循环“替换”递归“。

    15920

    调用优化

    这就是"调用优化"的意义。 三、递归 函数调用自身,称为递归。如果调用自身,就称为递归。...ES6也是如此,第一次明确规定,所有 ECMAScript 的实现,都必须部署"调用优化"。这就是说,在 ES6 中,只要使用递归,就不会发生栈溢出,相对节省内存。...这样做的缺点就是不太直观,第一眼很难看出来,为什么计算5的阶乘,需要传入两个参数5和1? 两个方法可以解决这个问题。方法一是在递归函数之外,再提供一个正常形式的函数。...总结一下,递归本质上是一种循环操作。纯粹的函数式编程语言没有循环操作命令,所有的循环都用递归实现,这就是为什么递归对这些语言极其重要。...对于其他支持"调用优化"的语言(比如Lua,ES6),只需要知道循环可以用递归代替,而一旦使用递归,就最好使用递归

    78050

    Mobius 一个运行在 .NET Core 上的 .NET 运行时

    换句话是不要 Native 的本机代码或 C++ 代码,所有的代码都是通过 C# 编写是否有可能?这看起来是一个无穷的递归,用 .NET 写 .NET 的运行时运行在 .NET 的运行时上。...但是如果应用是热启动,那么意味着此时运行的代码生成质量可以依托对CPU的优化,可以达到比本机代码更好的性能。使用 C# 开发理论上可以使用更加稳健的优化。...同样用 C# 写 GC 也能有相同的提升 用于玩闹。对于很多人来说,例如德熙看着这个项目一步步搭建起来是十分有趣的 如上面说的,其实都不是很强的理由,为什么要用 .NET 去写 .NET 运行时。...这就允许咱假设在一个正常运行的应用程序中,大部分在 Mobius 层的内容都是经过了 JIT 编译优化完成之后运行的,这包括了常用的对 .NET Core 代码的 JIT 构建的代码,这将十分接近 .NET...目前所有需要的机制都已就绪,包括:即使编译的基础支持,通过托管调用 JIT 代码,通过 JIT 代码调用 Mobius 框架。

    69810

    Mobius 一个运行在 .NET Core 上的 .NET 运行时

    换句话是不要 Native 的本机代码或 C++ 代码,所有的代码都是通过 C# 编写是否有可能?这看起来是一个无穷的递归,用 .NET 写 .NET 的运行时运行在 .NET 的运行时上。...但是如果应用是热启动,那么意味着此时运行的代码生成质量可以依托对CPU的优化,可以达到比本机代码更好的性能。使用 C# 开发理论上可以使用更加稳健的优化。...同样用 C# 写 GC 也能有相同的提升 用于玩闹。对于很多人来说,例如德熙看着这个项目一步步搭建起来是十分有趣的 如上面说的,其实都不是很强的理由,为什么要用 .NET 去写 .NET 运行时。...这就允许咱假设在一个正常运行的应用程序中,大部分在 Mobius 层的内容都是经过了 JIT 编译优化完成之后运行的,这包括了常用的对 .NET Core 代码的 JIT 构建的代码,这将十分接近 .NET...目前所有需要的机制都已就绪,包括:即使编译的基础支持,通过托管调用 JIT 代码,通过 JIT 代码调用 Mobius 框架。

    36720

    调用递归

    因此,严格模式(strict mode)禁止这些属性,并且调用优化只在严格模式下有效。 如果调用优化生效,流程图就会变成这样: ?...这就叫做调用优化,如果所有的函数都是调用的话,那么在调用栈中的调用帧始终只有一条,这样会节省很大一部分的内存,这也是调用优化的意义。 递归 1....那么什么是递归? 前面我们知道了调用的概念,当一个函数调用自身,就叫做递归。 function foo () { return foo(); } 复制代码 2....由此可见,调用优化递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。 避免改写递归函数 递归的实现,往往需要改写递归函数,确保最后一步只调用自身。...要注意的是,经过测试,Chrome和Firefox并没有对调用进行优化,Safari对调用进行了优化。 Node高版本也已经去除了通过--harmony_tailcalls参数启用调用优化

    1.1K10

    调用递归

    调用优化中,这些属性不再有用,因为相关的信息可能以及被移除了。...这就叫做调用优化,如果所有的函数都是调用的话,那么在调用栈中的调用帧始终只有一条,这样会节省很大一部分的内存,这也是调用优化的意义。 递归 1....那么什么是递归? 前面我们知道了调用的概念,当一个函数调用自身,就叫做递归。 function foo () { return foo(); } 2....由此可见,调用优化递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。 避免改写递归函数 递归的实现,往往需要改写递归函数,确保最后一步只调用自身。...要注意的是,经过测试,Chrome和Firefox并没有对调用进行优化,Safari对调用进行了优化。 Node高版本也已经去除了通过--harmony_tailcalls参数启用调用优化

    9610
    领券