阅读目录:

  1. 递归运用
  2. 尾递归优化
  3. 编译器优化

递归运用

一个函数直接或间接的调用自身,这个函数即可叫做递归函数。

  • 递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果。
  • 递归最重要的是边界条件,这个边界是整个递归的终止条件。

static int RecFact(int x)
{
if (x == )
return ;
return x * RecFact(x - );
}
RecFact();

上面是个经典阶乘函数的实现。这里分2步:

  • 转换,把10的阶乘转化成10*9!,10(9*8!)....每次转换规模就变的更小。
  • 逼近,转换到最小规模时0!,求解1。开始逆向合并逐渐逼近到10,得出解。

这里的x==0就是我们的边界条件(即终止条件),也有的依赖外部变量为边界。

如果一个递归函数没有边界,也就无法停止(无限循环至内存溢出),当然这样也没什么意义。

RecFact调用堆栈:

常见使用场景:

  • 阶乘/斐波那契数列/汉诺塔
  • 遍历硬盘文件
  • InnerExceptions异常扑捉(exception.InnerException==null)

尾递归优化

当边界不明确的时候,递归就很容易出现溢出问题。

在阶乘过程中,堆栈需要保存每次(RecFact)调用的返回地址及当时所有的局部变量状态,期间堆栈空间是无法释放的(即容易出现溢出)。

为了优化堆栈占用问题,从而提出尾递归优化的办法。

    static void TailRecursion(int x)
{
Console.WriteLine(x);
if (x == )
return;
TailRecursion(x + );
}
TailRecursion();

使用尾递归堆栈可以不用保存上次的函数返回地址/各种状态值,而方法遗留在堆栈上的数据完全可以释放掉,这是尾递归优化的核心思想。

由于尾递归期间,堆栈是可以释放/再利用的,也就解决递归过深而引起的溢出问题,这也是尾递归的优势所在。

编译器优化

尾递归优化,看起来是蛮美好的,但在net中却有点乱糟糟的感觉。

  • Net在C#语言中是JIT编译成汇编时进行优化的。
  • Net在IL上,有个特殊指令tail去实现尾递归优化的(F#中)。

我们执行 TailRecursion(0)(x==1000000) 得出如下结论:

C#/64位/Release是有JIT编译器进行尾递归优化的(非C#编译器优化)。

C#/32位或C#/Debug模式中JIT是不进行优化的。

F#在优化尾递归也分2种情况:

1、 简单的尾递归优化成while循环,如下:

 let rec TailRecursion(x) =
if (x = ) then true
else TailRecursion(x + )

(方便演示C#呈现)编译器优化成:

    public static bool TailRecursion(int x)
{
while (x != 0x3e8)
{
x++;
}
return true;
}

2、 复杂的尾递归,F#编译器会生成IL指令Tail进行优化,如下:

let TailRecursion2 a cont = cont (a + )  

优化成:

如何定义复杂的尾递归呢?通常是后继传递模式(CPS)。

F#中在debug模式下,需要在编译时配置:

总结

在C#语言(过程式/面向对象编程思想)中,优先考虑的是循环,而不是递归/尾递归。 但在函数式编程思想当中,递归/尾递归使用则是主流用法,就像在C#使用循环一样。

参考资料

http://volgarev.me/blog/62412678347

http://stackoverflow.com/questions/15864670/generate-tail-call-opcode

探索c#之尾递归编译器优化的更多相关文章

  1. VS编译器优化诱发一个的Bug

    VS编译器优化诱发一个的Bug Bug的背景 我正在把某个C++下的驱动程序移植到C下,前几天发生了一个比较诡异的问题. 驱动程序有一个bug,但是这个bug只能 Win32 Release 版本下的 ...

  2. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part6:Move语义和编译器优化

    本文为第六部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  3. Visual C++中的编译器优化

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:Visual C++中的编译器优化.

  4. gcc编译器优化给我们带来的麻烦???

    gcc编译器优化给我们带来的麻烦??? 今天看到一个很有趣的程序,如下: ? 1 2 3 4 5 6 7 8 9 int main() {     const int a = 1;     int * ...

  5. C#编译器优化那点事

    使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的. 优化代码开关即optimize开 ...

  6. 【转】C 编译器优化过程中的 Bug

    C 编译器优化过程中的 Bug 一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为.这使我想起以前见过的一个 GCC bug ...

  7. C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理

    C#编译器优化那点事   使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...

  8. C#编译器优化

    C#编译器优化 https://www.cnblogs.com/podolski/p/8987595.html 使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置 ...

  9. 2018-8-10-win10-uwp-禁止编译器优化代码

    title author date CreateTime categories win10 uwp 禁止编译器优化代码 lindexi 2018-08-10 19:16:50 +0800 2018-2 ...

随机推荐

  1. 重写AgileEAS.NET SOA 中间件平台账号密码的加密算法

    一.平台简介 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适 ...

  2. Xamarin教程索引页

    持续更新中-- 近期学习处理Xamarin.Android动画内容 Xamarin指南 -- 官网教程翻译 Xamarin跨平台开发 Xamarin Workbooks Xamarin Workboo ...

  3. VadRoot枚举进程模块在Windows7下的完整实现

      原理小伟的小伟在http://bbs.pediy.com/showthread.php?t=66886说的挺清楚了,Windows7下有一些变化,使用NtQueryVirtualMemory来枚举 ...

  4. java对象转换成json

    package com.bjs.acrosstime.utils; import java.util.ArrayList; import java.util.Date; import java.uti ...

  5. 自定义RatingBar的一个问题(只显示显示一个星星)

    问题一: 在自定义RatingBar时在设置了numStars属性后只显示一张图(一个星星) 解答: 注意准备的替换图片千万不要使用.9PNG格式的图片,要不之后显示一张图(一个星星)! 问题二: 设 ...

  6. 如何在Web引用中使用项目自定义的类

    这个是老架构了,不推荐现在这么用,维护一个老项目记录一下. 项目中WebService和客户端是在一个解决方案下,实体类是一个公用的Project,如果使用Web引用自动生成的类会缺少一些实体类定义的 ...

  7. Android 利用RecyclerView.Adapter刷新列表中的单个view问题

    首先使用RecyclerView的adapter继承:RecyclerView.Adapter public class OrderListAdapter extends RecyclerView.A ...

  8. 简述TCP连接的建立与释放(三次握手、四次挥手)

    在介绍TCP连接的建立与释放之前,先回顾一下相关知识. TCP是面向连接的运输层协议,它提供可靠交付的.全双工的.面向字节流的点对点服务.HTTP协议便是基于TCP协议实现的.(虽然作为应用层协议,H ...

  9. penpyxl basic function demo code

    Openpyxl basic function demo code demo code: #!/usr/bin/env python # -*- coding: utf-8 -*- "&qu ...

  10. JDBC驱动自身问题引发的FullGC

    公众号HelloJava刊出一篇<MySQL Statement cancellation timer 故障排查分享>,作者的某服务的线上机器报 502(502是 nginx 做后端健康检 ...