性能优化(四)高CPU利用率

针对一个高负载API进行性能优化,通过减少单次查询数据量并利用HashMap合并数据,有效降低了CPU使用率及响应时间,但增加了GC频率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

还是上一篇中提到过的API,通过调查我们发现这个API在需要返回的数据量比较大的有些单次调用中CPU可能达到90%到100%。所以即便是调用量不大的情况下,这个API一样是造成整个系统性能低下的最大贡献者。其中有一次调用返回时间更是长达10s。其实CPU的使用率高的话,响应时间自然就长,需要很长时间的计算才可以返回。

优化的思路还是把单个查询分成多次,降低每次返回的数据集的大小。数据量比较大的表最好是单独查询,不要去和其他表join。比如一张表中我们查出的结果集是10k,和另外一个只有20的结果集相乘就是几十万了,随便再jion一两个表就上百万了。凡是上万的结果集我都不太放心,更不要提10万,百万。另外一个好处是,单独查这一张表的时候不用去LEFT JOIN,INNER JOIN可以解决所有问题,而且JOIN后面的表都是unique的record。有一个查询的结果集特别大,通过分析后我认为是因为查询的时间范围很广,有13个月的结果。为了进一步让单个查询的结果集变小,决定用时间段来分割。比如分成两次查询,各查半年左右。总之我的原则就是单次查询的结果集要小,这样给MyBatis去处理结果集的压力就小。通过对每次查询打印执行时间可以看出来,结果集大的时候返回特别慢,而且CPU也很高,通过工具可以看到ResultSet的getLong,getString等方法调用次数很多。如果还有很多typeHandler那给Mybatis的压力就更大了。

这样分了之后单次查询返回的时间很快。但是问题就是怎么把这些数据合并起来。因为是树状结构的数据,相当于从根部要获得叶子。给你一个“师”的ID,需要查出所有他小面的各级单位的各种数据。一个SQL join到底的结果就是结果集很大,我的做法是一个SQL查出所有“旅”,一个SQL再查出所有“团”,依次类推。如何把这些数据合并呢?一级一级去循环遍历的话必然是一个多层的循环。想象一个5层的循环,没有哪一个程序员愿意这样写。我的解决方案是用HashMap,这就是Hash的好处,寻址很快,不用遍历去找。这样的话避免了多层循环,多层循环的时间复杂度应该是O(n*m*L....),这样改写之后至少可以变成O(n+m+l....)。还是空间换时间的做法,结果也可想而知,就是产生的临时变量很多,GC很频繁,minor GC很频繁。性能测试之后发现,当TPS到100左右的时候CPU的GC占比有时会有10%左右。但是暂时没有想到更好的办法,目前也还在这个项目可以接受的范围。希望以后能想到更好的办法。不过更好的办法可能是改写需求,让这个API不要一次性返回那么多数据,也就没有挑战性了。。

<think>我们参考用户的问题和提供的引用来回答如何优化CPU利用率低的问题。用户特别询问了如何使用VS性能探查器。根据引用[3][4],我们可以按照以下步骤进行:1.使用VS性能探查器收集性能数据,特别是CPU使用率。2.分析数据,定位热点函数。3.根据分析结果优化代码。具体步骤如下:步骤1:使用VS性能探查器进行性能测试打开VisualStudio->菜单栏选择“分析”->“性能探查器”。选择“CPU使用率”工具,点击开始,运行程序,模拟实际使用场景,然后停止收集。步骤2:分析性能数据收集完成后,会生成报告。根据引用[3]:-在报告视图中,可以选择不同的视图方式,例如“调用方/被调用方”、“调用树”、“模块”、“函数”、“火焰图”(VS2022支持)。-重点关注“函数”视图:可以看到每个函数的CPU占用百分比,双击函数名可以定位到源代码。-如果使用VS2022,火焰图视图可以更直观地看到函数调用关系和耗时比例。步骤3:定位性能瓶颈通过查看函数视图,找到CPU占用率的函数(热点函数)。分析该函数为什么占用,可能是由于循环、复杂计算、频繁调用等。引用[2]中提到,CPU瓶颈可能由于绘制调用准备、物理模拟、光照或阴影等因素。在游戏中,也可能是因为复杂的逻辑运算。步骤4:优化代码针对热点函数进行优化。常见的优化方法包括:-算法优化:使用更效的算法。-减少不必要的计算:缓存中间结果,避免重复计算。-并行化:使用多线程或并行计算(如使用OpenMP、TBB等)。-向量化:使用SIMD指令优化。-减少锁竞争:对于多线程程序,优化锁的使用。注意:修改代码后,重复步骤1-3,验证优化效果,直到达到性能目标(引用[4]的流程图)。示例:假设分析发现函数`A`的CPU占用率很,它的主要工作是在一个循环内处理大量数据。我们可以尝试优化:```c++//原代码voidA(){for(inti=0;i<large_number;i++){//复杂计算...}}```优化方法1:并行化```c++#include<ppl.h>voidA_optimized(){concurrency::parallel_for(0,large_number,[](inti){//复杂计算...});}```优化方法2:循环展开或向量化(需要结合具体计算)步骤5:其他注意事项引用[2]提到,对于VR游戏,CPU优化可以提升GPU利用率。因此,在优化CPU后,可能还需要关注GPU瓶颈。总结:使用VS性能探查器的CPU使用率工具定位热点函数,然后根据原因采取相应的优化措施,通过多次迭代测试和优化逐步提升性能。§§相关问题§§1.除了VS性能探查器,还有哪些CPU性能分析工具?2.多线程编程中如何避免锁竞争?3.如何对内存使用进行优化以减少CPU开销?</think> ### 使用 VS 性能探查器优化 CPU 利用率低的步骤 #### **1. 启动性能分析** [^3][^4] - 在 Visual Studio 中打开项目 → 顶部菜单选择“分析” → “性能探查器” - 选择 **“CPU 使用率”** 工具 → 点击 **“开始”** 运行程序 - 复现低 CPU 利用率的场景后停止收集数据 #### **2. 分析性能报告** [^3] 在生成的报告中: - **查看函数视图**: 直接定位 CPU 占用最的函数(按总时间%排序) ```mermaid graph LR A[函数视图] --> B(双击耗时函数) B --> C[定位到源代码] ``` - **使用火焰图(VS2022+)**: 可视化调用栈层级,快速识别深度调用链中的热点 - **检查调用树**: 适用于浅调用栈,分析函数调用关系 - **模块视图**: 查看动态库的 CPU 消耗占比 #### **3. 关键优化点** [^2][^4] | 问题类型 | 优化方向 | 检查工具 | |----------|----------|----------| | 频繁函数调用 | 缓存结果/减少调用次数 | 函数视图 | | 低效算法 | 替换算法复杂度 | CPU 占用%对比 | | 锁竞争 | 减少同步等待 | 线程视图 | | 冗余计算 | 预计算/向量化 | 火焰图调用链 | #### **4. 修改与验证** [^4] 1. 修改热点函数代码(示例): ```csharp // 优化前:频循环中重复计算 for (int i=0; i<10000; i++) { result += ExpensiveCalculation(); } // 优化后:预计算结果 var precomputed = ExpensiveCalculation(); for (int i=0; i<10000; i++) { result += precomputed; } ``` 2. **重新运行性能探查器** → 对比优化前后 CPU 占用率 3. 若未达标,回到步骤 2 分析新热点 #### **5. 特殊场景处理** [^2] - **对 GPU 性能优化**:当 CPU 瓶颈解除后,切换工具到 **“GPU 使用率”** 继续优化 - **多线程分析**:使用 **“并发可视化”** 工具检查线程阻塞问题 --- ### 常见 CPU 瓶颈原因 1. **过度绘制调用**:批处理图形 API 调用(减少 Draw Call) 2. **物理模拟开销**:降低碰撞检测频率或简化物理网格 3. **光照/阴影计算**:使用烘焙光照代替实时计算 4. **复杂逻辑分支**:使用查找表代替条件判断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值