【C++】编程规范之性能优化

性能优化流程

  1. 找到性能热点代码
    在进行性能优化之前,首先需要确定哪些部分是代码的性能热点。可以使用性能分析工具(如 simpleperf)生成火焰图,识别程序中的瓶颈。

  2. 确定性能问题、原因和优化方案
    通过分析火焰图,确定性能问题的具体位置和原因。性能问题可能来自算法设计不合理、代码流程不够高效,或者资源(如计算资源或IO资源)未被充分利用。根据问题的具体情况,提出相应的优化方案。

  3. 解决问题
    根据确定的优化方案,对代码进行修改和优化,以提高性能。

遵循优化规则

  1. 使用更低比特的位宽
    在适当的情况下,可以考虑使用更低比特的数据类型来节省内存空间和提高计算效率,但要确保不会损失精度。
// 示例:使用 uint8_t 代替 int,节省内存空间
uint8_t num = 10;
  1. Cache 友好的内存存取方式
    尽量利用 Cache 以提高内存访问效率,可以通过顺序访问数组、结构体内存布局优化等方式实现。
// 示例:优化数组遍历顺序以提高 Cache 命中率
for (int i = 0; i < size; ++i) {// 顺序访问数组元素
}

两个关键概念:
时间局部性:指程序中的某个数据项在一段时间内可能被多次使用。例如,在一个循环中反复访问相同的数组元素。
空间局部性:指程序中的某个数据项在一段时间内可能被多次使用其附近的数据。例如,数组元素的访问往往是顺序的或近乎顺序的。

考虑以下两种访问二维数组的方式:

// 不友好的访问方式
int array[N][N];
for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {// 访问数组元素array[i][j] = i + j;}
}// 友好的访问方式
int array[N][N];
for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {// 访问数组元素array[j][i] = i + j;}
}

在第一个例子中,内层循环的访问是按行进行的,这可能导致不同行之间的数据不连续存储,降低了 Cache 的命中率。而在第二个例子中,内层循环的访问是按列进行的,这有利于提高空间局部性,使得 Cache 能够更好地工作,提高了访问效率。

  1. 循环嵌套遵循外小内大原则
    在嵌套循环中,外层循环应该尽量简单,内层循环应该尽量复杂,以减少循环次数和提高 Cache 命中率。
//rows>cols
// 不友好的循环嵌套方式
for (int i = 0; i < rows; ++i) {for (int j = 0; j < cols; ++j) {// 复杂的内层循环操作}
}// 友好的循环嵌套方式
for (int j = 0; j < cols; ++j) {for (int i = 0; i < rows; ++i) {// 复杂的内层循环操作}
}
  1. 循环体内尽量避免分支、函数调用、重复计算、内存申请等操作
    在循环体内,尽量减少分支语句、函数调用、重复计算和内存申请等耗时操作,以提高循环执行效率。

避免分支:尽量减少使用分支语句,特别是在内层循环中,因为分支语句可能导致流水线的中断,影响性能。

// 不友好的分支使用
if (condition) {// 分支内操作
} else {// 分支内操作
}// 友好的分支使用
result = condition ? value1 : value2;

避免函数调用:尽量减少在循环内部的函数调用,因为函数调用涉及栈操作和跳转,会增加额外的开销。

// 不友好的函数调用
for (int i = 0; i < size; ++i) {result += func(array[i]);
}// 友好的函数调用
int temp;
for (int i = 0; i < size; ++i) {temp = array[i];result += temp * temp; // 重复计算问题
}

避免重复计算:在循环内部尽量避免重复计算相同的值,可以使用临时变量存储中间结果,以提高执行效率。
5. 循环展开
循环展开可以减少循环控制开销,提高指令级并行度,以及利用向量指令优化循环执行效率。

循环展开可以通过手动展开或者编译器指令展开来优化循环执行效率。

手动展开:

// 手动展开循环
for (int i = 0; i < size; i += 5) {result += array[i] + array[i+1] + array[i+2] + array[i+3] + array[i+4];
}

编译器指令展开:

// 使用编译器指令展开循环
#pragma unroll(5)
for (int i = 0; i < size; ++i) {result += array[i];
}
  1. 复合语句中将复杂表达式放后面
    在复合语句中,将复杂表达式放在后面,以避免不必要的计算。
    表达式优化可以通过重排计算顺序、利用短路求值等方式提高程序执行效率。

短路求值示例:

// 不友好的表达式
if (a == 0 || b / a > c) {// 表达式操作
}// 友好的表达式
if (a != 0 && b / a > c) {// 表达式操作
}
  1. 函数设计上参数数量小于 4
    在函数设计时,尽量保持参数数量的少量,以减少函数调用的开销和提高代码可读性。

函数参数的数量限制通常是由硬件平台和编译器规定的。在 x86-64 架构中,前 6 个参数通过寄存器传递,之后的参数通过栈传递。因此,通常建议将参数数量限制在 4 个以内,以避免过多参数的传递开销。

友好的函数参数示例:

// 不友好的函数参数
void processData(int a, int b, int c, int d, int e) {// 函数操作
}// 友好的函数参数
struct Parameters {int a;int b;int c;int d;
};void processData(const Parameters& params, int e) {// 使用结构体传递参数
}

在这个示例中,将参数封装为一个结构体 Parameters,通过引用或指针传递,避免了过多参数的传递开销。此外,结构体参数的方式也更具可读性和可维护性

  1. 使用多线程
    在合适的情况下,可以使用多线程并行执行任务,以充分利用多核处理器的计算资源。
// 示例:使用多线程并行执行任务
std::thread t1(task1);
std::thread t2(task2);
t1.join();
t2.join();
  1. 合理使用 STL
    在使用 STL(标准模板库)时,注意选择适当的数据结构和算法,并合理利用其提供的功能,如使用 reserve 预分配内存来避免动态内存分配的开销。
// 示例:使用 reserve 预分配内存
std::vector<int> vec;
vec.reserve(1000); // 预分配内存
  1. 大文件存取使用 C 库函数
    对于大文件的读写操作,使用 C 库函数(如 fopen、fread、fwrite 等)而不是 C++ 的 fstream,以提高 IO 效率。
// 示例:使用 C 库函数进行大文件读写操作
FILE* file = fopen("large_file.bin", "rb");
// 读取文件内容
fclose(file);
  1. 数据对齐
    数据对齐是指数据存储在内存中时按照一定的规则进行排列,以便于提高访问效率。在许多计算机体系结构中,访问未对齐的数据会导致额外的开销和性能损失。

友好的数据对齐示例:

struct Data {int a;float b;char c;
};// 友好的数据对齐
struct DataAligned {int a;char padding1[4]; // 补齐到 8 字节float b;char c;
};

在这个示例中,结构体 DataAligned 中的成员 a 和 b 分别是 4 字节和 4 字节对齐的,因此不需要额外的补齐;而 c 则是 1 字节对齐的。通过合理地安排成员的顺序和增加填充字节,可以使整个结构体的大小为 12 字节,保证了数据对齐,提高了访问效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/793695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA毕业设计133—基于Java+Springboot+Vue的网上宠物店商城管理系统(源代码+数据库+12000字论文)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的网上宠物店商城管理系统(源代码数据库12000字论文)133 一、系统介绍 本项目前后端分离&#xff0c;分为管理员、用户两种角色 1、用户&#xff1a; 注册…

python-基础篇-字符串、列表、元祖、字典-字符串

文章目录 2.3字符串、列表、元祖、字典2.3.1字符串2.3.1.1字符串介绍2.3.1.1.1python中字符串的格式&#xff1a;2.3.1.1.2字符串在内存中的存储方式 2.3.1.2字符串的输入输出2.3.1.2.1字符串输出2.3.1.2.2字符串输入2.3.1.2.3组字符串的方式 2.3.1.3下标和切片2.3.1.3.1下标索…

Android 系统大致启动流程

Android启动流程大体为&#xff1a;BootRom -> BootLoader -> Kernel -> Init -> Zygote -> SystemServer ->Launcher 1、Loader层 1.1、Boot ROM 电源按下&#xff0c;引导芯片代码开始从预定义的地方&#xff08;固化在ROM&#xff09;开始执行&#xff0…

Unity入门

Unity入门学习 知识概述&#xff1a; Unity环境搭建 1.Unity引擎是什么 2.软件下载安装 下载最新的长期支持版即可 3.新工程和工程文件夹 Unity界面基础 1.Scene场景和Hierachy层级窗口 练习&#xff1a; 2.Game游戏和Project工程 3.Inspector检查和Console控制台 练习&#…

医疗器械5G智能制造工厂数字孪生可视化平台,推进行业数字化转型

医疗设备5G智能制造工厂数字孪生可视化平台&#xff0c;推进行业数字化转型。在数字化浪潮的推动下&#xff0c;医疗设备行业正迎来一场深刻的变革。5G技术的崛起&#xff0c;智能制造工厂的兴起&#xff0c;以及数字孪生可视化平台的出现&#xff0c;正在共同推动医疗设备行业…

英语语法总结(1)

名词 &#xff08;1&#xff09;专有名词China &#xff08;2&#xff09;普通名词{ 个体名词horse 集体名词people 物质名词fire 抽象名词labor }可数名词{ 个体名词a book 集体名词 My family is a large one(整体) My family are all music lovers(个体) &#xff08;若作为…

编程基础---C/C++基础知识

语法和语义 变量定义 基本数据类型&#xff1a;定义整型&#xff08;int、long、short&#xff09;、浮点型&#xff08;float、double&#xff09;、字符型&#xff08;char&#xff09;等基本数据类型的变量。 自定义类型&#xff1a;定义结构体、联合体、枚举等自定义类…

react组件:profiler

React Profiler 主要用于开发过程中的性能分析和优化&#xff0c;而不应在生产环境中使用&#xff0c;因为它可能会对性能产生一定的影响。 使用 包裹组件树&#xff0c;以测量其渲染性能。 ** id&#xff1a;字符串&#xff0c;用于标识正在测量的 UI 部分。 onRender&a…

Xshell Plus 详细安装教程以及附带使用图文教程

一、下载 Xshell Plus 6 完成后&#xff0c;请按照下面教程操作 1、下载 Xshell Plus 6 完成后&#xff0c;并解压 zip 包: 2、进入解压后的文件夹后&#xff0c;如果你之前安装了 Xshell&#xff0c; 先点击 !卸载.bat 卸载 xshell&#xff0c; 然后再点击 !绿化.bat; 如果是…

二分答案(砍树,借教室)

二分的两种情况附代码&#xff1a; 二分查找条件&#xff1a;单调&#xff0c;二段性 例题1&#xff1a;P1873 [COCI 2011/2012 #5] EKO / 砍树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 上代码&#xff1a; #include<bits/stdc.h> using namespace std; const …

校招说明书

3400字的详细说明&#xff0c;介绍了程序员类岗位校招的整体时间节点和招聘流程。还对一些常见的问题进行讨论&#xff0c;例如内推、offer和三方、实习等。 第一章介绍基本的术语&#xff0c;第二章介绍整个校招的重要流程及时间点&#xff0c;然后第三章介绍每次招聘要经过的…

什么是jQuery?怎么使用?

​ 文章目录 一、jQuery是什么二、dom对象和jQuery对象1、DOM对象可以和jQuery对象相互的转换 三、基本选择器1、元素选择器&#xff1a;根据HTML元素的名称选择元素2、ID选择器&#xff1a;通过元素的ID属性选择元素3、类选择器&#xff1a;通过元素的class属性选择元素4、通…

MySql 实战大数据查询-(表分区实现)

一 mysql分区&#xff1a; 分区是将单个表按照某种规则划分成多个子集&#xff0c;每个子集称为一个分区。常见的分区策略包括按照时间范围、范围值、列表等进行分区。 优点&#xff1a; 查询性能更好&#xff0c;涉及分区键的查询&#xff0c;数据库引擎可以只扫描特定分区&…

易宝OA ExecuteQueryForDataSetBinary SQL注入漏洞复现

0x01 产品简介 易宝OA系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台,具有信息管理、 流程管理 、知识管理(档案和业务管理)、协同办公等多种功能。 0x02 漏洞概述 易宝OA ExecuteQueryForDataSetBinary 接口处存在SQL注入漏洞,未经身份认证的攻击者…

Word中插入Endnote参考文献时显示乱码

近期在写文章需要插入参考文献&#xff0c;使用Endnote插入时显示乱码&#xff0c;如下图所示&#xff1a; 文章末尾显示{ADDIN EN REFILIST } 解决方法 在网上找了诸多方法尝试也没有解决&#xff0c;最终找到一篇博客介绍了一种方法&#xff1a; word选项—高级&#xff1…

openGauss学习笔记-256 openGauss性能调优-使用Plan Hint进行调优-优化器GUC参数的Hint

文章目录 openGauss学习笔记-256 openGauss性能调优-使用Plan Hint进行调优-优化器GUC参数的Hint256.1 功能描述256.2 语法格式256.3 参数说明 openGauss学习笔记-256 openGauss性能调优-使用Plan Hint进行调优-优化器GUC参数的Hint 256.1 功能描述 设置本次查询执行内生效的…

LAN和WAN, 调制解调器, 路由器,交换机 区别

LAN LAN&#xff08;Local Area Network&#xff09;是指在相对较小的地理范围内&#xff08;如办公室、学校、实验室、家庭等&#xff09;连接在一起的计算机和网络设备的集合。LAN通常由路由器、交换机、网线、无线路由器等设备组成&#xff0c;用于连接多台计算机、打印机、…

react状态管理库---zustand

一个简单的&#xff0c;快速的状态管理解决方案&#xff0c;api设计基于函数式和hooks 安装&#xff1a; npm install zustand 基础使用 让我们实现一个非常简单的计数器案例完成我们的第一个store 1- 创建一个counterStore create( ) 有三个参数&#xff1a;函数、布尔值…

Leetcode - 127双周赛

目录 一&#xff0c;3095. 或值至少 K 的最短子数组 I 二&#xff0c;3096. 得到更多分数的最少关卡数目 三&#xff0c;3097. 或值至少为 K 的最短子数组 II 四&#xff0c;3098. 求出所有子序列的能量和 一&#xff0c;3095. 或值至少 K 的最短子数组 I 本题需要知道一个知…

认识c++链表

上次发了《C链表&#xff08;上&#xff09;》&#xff0c;今天我再发一个认识c链表 C中的链表是一种常见的数据结构&#xff0c;用于存储和组织数据。链表由一系列节点组成&#xff0c;每个节点包含一个值和一个指向下一个节点的指针。链表的优点是可以在运行时动态地增加或删…