代码调优法则

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实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

python多进程实现数据共享的示例代码

《python多进程实现数据共享的示例代码》本文介绍了Python中多进程实现数据共享的方法,包括使用multiprocessing模块和manager模块这两种方法,具有一定的参考价值,感兴趣的可以... 目录背景进程、进程创建进程间通信 进程间共享数据共享list实践背景 安卓ui自动化框架,使用的是

SpringBoot生成和操作PDF的代码详解

《SpringBoot生成和操作PDF的代码详解》本文主要介绍了在SpringBoot项目下,通过代码和操作步骤,详细的介绍了如何操作PDF,希望可以帮助到准备通过JAVA操作PDF的你,项目框架用的... 目录本文简介PDF文件简介代码实现PDF操作基于PDF模板生成,并下载完全基于代码生成,并保存合并P

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里