代码调优法则

2024-06-23 15:32
文章标签 代码 法则 调优

本文主要是介绍代码调优法则,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《编程珠玑》第二版快看完了,发现附录D作者记录了一些代码调优法则,本人总结了一下,发出来给大家分享分享,顺便自己也做个笔记。(注:这篇文章是用那个markdown写的,第一次用markdown发布博客,有点小激动。)

代码调优法则

空间换时间法则

  • 修改数据结构。为了减少数据上的常见运算所需要的时间,我们通常可以在数据结构中增加额外的信息,或者修改数据结构中的信息使之更易访问。
    例如:std::vector中的empty和size成员函数之类的。
  • 存储预先计算好的结果。对于开销较大的函数,可以只计算一次,然后将计算结果存储起来以减少开销。以后再需要该函数时,可以直接查表而不需要重新计算。
    例如:读取文件中的数据时不用每次都去读取,第一次读取出来时保存数据即可。
  • 高速缓存。最经常访问的数据,其访问开销应该是最小的。
  • 懒惰求值。除非需要,否则不对任何一项求值。这一策略可以避免对不必要的项求值。
    例如:类模板中只对使用到的成员函数实例化。

时间换空间法则

  • 堆积。密集存储表示可以通过增加存储和检索数据所需的时间来减少存储开销。
    例如:使用数组来表示稀疏矩阵。
  • 解释程序。使用解释程序通常可以减少表示程序所需的空间,在解释程序中常见的操作序列以一种紧凑的方式表示。

循环法则

  • 将代码移出循环。与其在循环的每次迭代时都执行一次某种计算,不如将其移到循环体外,只计算一次。
  • 合并测试条件。高效的内循环应该包含尽量少的测试条件,最好只有一个。因此,程序员应尽量用一些退出条件来模拟循环的其他退出条件。
    例如:哨兵是该法则的常见应用,在数据结构的边界上放一个哨兵以减少测试是否已搜索结束的开销。
  • 循环展开。循环展开可以减少修改循环下标的开销,对于避免管道延迟、减少分支以及增加指令级的并行性也都很有帮助。
  • 删除赋值。如果内循环中很多开销来自普通的赋值,通常可以通过重复代码并修改变量的使用来删除这些赋值。
  • 消除无条件分支。快速的循环中不应该包含无条件分支。通过“旋转”循环,在底部加上一个条件分支,能够消除循环结束处的无条件分支。该操作通常由编译器优化完成。
  • 循环合并。如果两个相邻的循环作用在同一组元素上,那么可以合并其运算部分,仅使用一组循环控制操作。

逻辑法则

  • 利用等价的代数表达式。如果逻辑表达式的求值开销太大,就将其替换为开销较小的等价代数表达式。
  • 短路单调函数。一旦找到了循环的目的就可以退出循环了。
  • 对测试条件重新排序。在组织逻辑测试的时候,应该将低开销的、经常成功的测试放在高开销的、很少成功的测试前面。
  • 预先计算逻辑函数。在比较小的有限域上,可以用查表来取代逻辑函数。
  • 消除布尔变量。我们可以用if-else语句来取代对布尔变量的赋值,从而取消程序中的布尔变量。

过程法则

  • 打破函数层次。对于(非递归地)调用自身的函数,通常可以通过将其改写为内联版本并固定传入的变量来缩短其运行时间。
  • 高效处理常见情况。应该使函数能正确处理所有情况,并能搞笑处理常见情况。
  • 协同程序。通常,使用协同例程能够将多趟算法转换为单趟算法。
  • 递归函数转换。递归函数的运行时间往往可以通过下面的转换来缩短:
    1.将递归重写为迭代,通过使用一个显式的程序栈将递归转化为迭代(如果函数仅包含一个对其自身的递归调用,那么就没有必要将返回地址存储在栈中);
    2.如果函数的最后一步是递归调用其自身,那么使用一个到其第一条语句的分支来替换该调用,这通常称为消除尾递归。该操作通常由编译器优化完成。
    3.解决小的子问题时,使用辅助过程通常比把问题的规模变为0或1更有效。例如:快速排序递归的规模小于50的时候不再递归,对整体数组使用一次插入排序比继续递归的速度更快。
  • 并行性。在底层硬件条件下,构建的程序应该尽可能多地挖掘并行性。

表达式法则

  • 编译时初始化。在程序执行之前,应该对使用到的变量初始化。
  • 利用等价的代数表达式。如果表达式的求值开销太大,就将其替换为开销较小的等价代数表达式。
    例如:使用if语句替换%取模运算。
  • 消除公共子表达式。如果两次对同一个表达式求值时,其所有变量都没有任何改动,那么我们可以用下面的方法避免第二次求值:存储第一次的计算结果并用其取代第二次求值。
    例如:第二次读取文件数据前检查文件的修改日期,若没有改变,则使用第一次读取的数据即可。
  • 成对计算。如果经常需要对两个类似的表达式一起求值,那么就应该建立一个新的过程,将它们成对求值。
  • 利用计算机字的并行性。用底层计算机体系结构的全部数据路径宽度来对高开销的表达式求值。

这篇关于代码调优法则的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087553

相关文章

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

python获取cmd环境变量值的实现代码

《python获取cmd环境变量值的实现代码》:本文主要介绍在Python中获取命令行(cmd)环境变量的值,可以使用标准库中的os模块,需要的朋友可以参考下... 前言全局说明在执行py过程中,总要使用到系统环境变量一、说明1.1 环境:Windows 11 家庭版 24H2 26100.4061

pandas实现数据concat拼接的示例代码

《pandas实现数据concat拼接的示例代码》pandas.concat用于合并DataFrame或Series,本文主要介绍了pandas实现数据concat拼接的示例代码,具有一定的参考价值,... 目录语法示例:使用pandas.concat合并数据默认的concat:参数axis=0,join=

C#代码实现解析WTGPS和BD数据

《C#代码实现解析WTGPS和BD数据》在现代的导航与定位应用中,准确解析GPS和北斗(BD)等卫星定位数据至关重要,本文将使用C#语言实现解析WTGPS和BD数据,需要的可以了解下... 目录一、代码结构概览1. 核心解析方法2. 位置信息解析3. 经纬度转换方法4. 日期和时间戳解析5. 辅助方法二、L

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

IIS 7.0 及更高版本中的 FTP 状态代码

《IIS7.0及更高版本中的FTP状态代码》本文介绍IIS7.0中的FTP状态代码,方便大家在使用iis中发现ftp的问题... 简介尝试使用 FTP 访问运行 Internet Information Services (IIS) 7.0 或更高版本的服务器上的内容时,IIS 将返回指示响应状态的数字代

JVisualVM之Java性能监控与调优利器详解

《JVisualVM之Java性能监控与调优利器详解》本文将详细介绍JVisualVM的使用方法,并结合实际案例展示如何利用它进行性能调优,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录1. JVisualVM简介2. JVisualVM的安装与启动2.1 启动JVisualVM2

MySQL 添加索引5种方式示例详解(实用sql代码)

《MySQL添加索引5种方式示例详解(实用sql代码)》在MySQL数据库中添加索引可以帮助提高查询性能,尤其是在数据量大的表中,下面给大家分享MySQL添加索引5种方式示例详解(实用sql代码),... 在mysql数据库中添加索引可以帮助提高查询性能,尤其是在数据量大的表中。索引可以在创建表时定义,也可