代码调优法则

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

相关文章

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

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

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