• 《程序员实用算法》试读:1.2.2主要的优化:函数调用


    另一个重要的优化是减少函数调用的次数。虽然现在许多编译器已经针对函数调用进行了重大优化,但是对于函数携带的重大开销还是稍存疑虑。为了验证这一点,我们可以编写一个小程序,它把一个只执行返回语句的函数调用了10 000次,你将开始感觉到函数调用的代价,如果函数传递参数或者返回值,那么花费的时间将会更长一些。常见的惯例是使用内联代码或者宏,把函数直接隐藏在算法中。研究编译器的库(如果可用,应该总是能得到源代码),并且你将会发现许多函数已经被实现为宏。要尽可能使用这些宏,并且要留心观察它们的副作用。如果你仍然必须调用函数并且不能获得所需的性能,可以考虑将供应商的源代码直接复制到你的算法中。这是一种危险的做法,仅当执行了所有其他的优化之后才应该考虑把它作为最后一种办法。除了版权问题之外,严格来讲,库的源代码也很少是可移植的,并且可能会处理隐藏在库内的变量。不过,可以轻松地引入许多函数或者把它们转换为宏。每种方法都会增加代码的大小,因此必须小心,不能过度使用这种技术。

    另一种常见的算法技术是消除递归。递归是使函数调用它自身的行为。在C语言中,所有的函数都可以进行递归调用:即它们都能调用自身,至少在理论上如此。实际上,像main()和exit()这样的函数在进行递归调用时可能会引发问题。不过,几乎所有不会终止程序的函数都可以调用它们自身。在算法中经常会使用递归技术,因为它可以产生短小、优雅的解决方案。不过,它的代价高昂,包括时间和系统资源两方面,尤其体现在栈空间的消耗上。第5章给出了关于如何消除递归的一些示例。在可能的情况下,应尽量避免使用递归。

    在MSDOS环境下,还有另外几种技术可用于减少函数调用的开销。首先,启用某些高级编译器提供的优化功能,它们允许使用寄存器而不是栈来传递函数参数(例如:Borland使用pr开关,Microsoft使用/Gr开关以及fastcall关键字,而Watcom则会默认执行优化)。如果用到了第三方程序库,在使用这些功能时就应该小心谨慎;有关更多信息,请参考相关的编译器文档。

    MSDOS用户的第二个选择是使用pascal关键字。它将影响被调用的函数如何操作栈。如果使用这个关键字,可以同时节省时间和空间。与上述的编译开关一样,也必须小心使用pascal关键字。它不能用于参数数量可变的函数,并且一般不能把它与上述的编译开关结合起来使用。同样,请认真阅读编译器文档。如果必须从这两种方法中选择一种,就必须检查你的程序。如果程序通常只传递数量很少的参数(但不是零个参数),就使用第一个选项;如果程序具有多种类型的函数,有的函数不带参数,有的函数则带有两个或三个以上的参数,那么pascal选项将更高效。

    最后,认真学习算法,然后钻研其中最频繁使用的部分。在这个过程中,拥有一种优秀的性能测量和跟踪工具(profiler)将给你带来巨大的好处。购买一种这样的工具并使用它;通过定期使用它可以加快代码的执行速度。在后面的各章中,在演示算法时我们强调了代码的清晰性。如果由于进行优化而使代码含义晦涩,我们将放弃这样做。只要有可能,我们就会给出关于在什么地方可以优化算法的提示和信息。
  • 相关阅读:
    A1023 Have Fun with Numbers [大整数乘法]
    大整数的四则运算
    A1096 Consecutive Factors [因子分解]
    A1078 Hashing [质数和散列结合]
    A1015 Reversible Primes [质数问题]
    又谈进制转换
    A1088 Rational Arithmetic [分数四则运算]
    A1081 Rational Sum [分数计算]
    linux主流系统配置静态ip
    主机ping虚拟机请求超时,虚拟机ping主机正常ping通导致ssh连接问题
  • 原文地址:https://www.cnblogs.com/shihao/p/2146478.html
Copyright © 2020-2023  润新知