编写高效程序需要做到以下几点:第一,我们必须选择一组适当的算法和数据结构。第二,我们必须编写出编译器能够有效优化以转换成高效可执行代码的源代码。第三项技术针对处理运算量特别大的计算,将一个任务分成多个部分,这些部分可以在多核和多处理器的某些组合上并行地计算。
现代编译器采用了复杂的分析和优化形式,而且变得越来越好。然而,即使是最好的编译器也受到*妨碍优化的因素(optimization blocker)*的阻碍,妨碍优化的因素就是程序行为中那些严重依赖于执行环境的方面。
程序优化的第一步就是消除不必要的工作,让代码尽可能有效地执行所期望的任务(不必要的函数调用、条件测试和内存引用)。
内联替换
什么是内联替换?
定义: 内联替换是编译器的一种优化技术,用于减少函数调用的开销。当你将一个函数标记为inline,编译器尝试将该函数的代码直接嵌入到每个调用点,而不是进行常规的函数调用。
如何工作: 在正常的函数调用中,程序在调用函数时需要跳转到函数的代码块,执行完毕后再跳回。这个过程涉及到一些开销,如保存调用点的信息、传递参数等。内联替换通过将函数的代码直接放置在调用点来避免这些开销。
它的作用是什么?
减少开销: 内联可以减少函数调用的开销,特别是对于小型、频繁调用的函数。
提高性能: 通过减少跳转和参数传递,内联可以提升程序的运行速度。
代码膨胀: 内联可能会导致代码大小的增加,因为相同的函数代码会被复制到每个调用点。因此,编译器通常会评估是否进行内联,以平衡性能和代码大小。
消除循环带来的低效率
举例可以看见

对于lower1来说每一次调用都调用了库函数strlen,而且他的返回结果都是一样的这样会显著增加性能开支,造成性能瓶颈。
消除不必要的内存引用
如图:

可以通过局部变量避免频繁的访问内存
循环展开
**循环展开(Loop Unrolling)**是一种编程优化技术,用于减少程序运行时循环的迭代次数,从而提高效率。这种技术通过减少循环中的控制指令(如跳转和比较)的执行频率,以及通过增加每次迭代中执行的操作数量来实现性能提升。
在没有展开的循环中,每次迭代通常只完成一小部分工作。循环展开通过在每次迭代中完成更多的工作来减少循环的总迭代次数。这可以通过几种方式实现,例如:
手动循环展开:程序员直接在代码中重写循环,以在每次迭代中执行更多的操作。例如,一个简单的循环,每次迭代加1,可以被展开为每次迭代加2、加4等。
自动循环展开:一些现代编译器能够自动识别循环展开的机会,并在编译时对循环进行优化。
循环展开的优点
减少循环开销:通过减少迭代次数,循环展开减少了每次迭代所需的控制指令的执行(如循环的比较和跳转指令)。
提高流水线效率:在每次迭代中执行更多的工作可以更好地利用处理器的指令流水线,尤其是在处理器可以同时执行多个独立操作的情况下。
增加指令级并行:循环展开有时可以提高指令级并行性,允许现代处理器同时执行更多独立的操作。
循环展开的缺点
增加代码大小:展开循环会增加程序的代码大小,这可能会导致更大的缓存占用和潜在的缓存不命中率增加。
可能影响缓存利用:更大的代码量可能不适合缓存,从而影响整体性能。
并非总是有效:在某些情况下,如循环体本身非常大或者循环迭代次数很少时,循环展开可能不会带来性能提升。
总之,循环展开是一种在许多情况下都能有效提升性能的技术,但它需要谨慎使用,特别是在处理器的缓存和流水线行为多样化的现代计算环境中。