c++性能优化策略

发布时间 2024-01-05 10:02:31作者: deeplearnMs

1-用好的编译器并用好编译器

C++ 编译器是非常复杂的软件构件。每种编译器为 C++ 语句生成的机器码都有差别。它们
所看到的优化机会是不同的,会为相同的源代码产生不同的可执行文件。如果打算为代码
做出最后一丁点性能提升,那么你可以尝试一下各种不同的编译器,看看是否有一种编译
器会为你产生更快的可执行文件

技巧:使用支持 C++11 的编译器C++11
现了右值引用(rvalue reference)和移动语义(move semantics,可以省去许多在以前的
C++ 版本中无法避免的复制操作

2.用好的编译器也意味着用好编译器。例如,如果应用程序非常缓慢,那么你应当检
查是否打开了编译器的优化选项。这条建议看似非常明显,但是我已经记不清有多少次我
向其他人提出这个建议后,他们都承认在编译时确实忘记打开优化选项了。多数情况下,
只要正确地打开了优化选项,你都不用做额外的优化,因为编译器就可以让程序的运行速
度提高数倍。


2-使用更好的算法

选择一个最优算法对性能优化的效果最大。各种优化手段都能改善程序的性能。它们可以
压缩以前看似低效的代码的执行时间,就像通过升级 PC 能让程序运行得更快一样。但不
幸的是,如同升级 PC 一样,大部分优化手段只能使程序性能呈线性提升。许多优化手段
可以将程序性能提升 30% 100%。如果足够幸运,也许你可以将性能提升至三倍。但是
除非你能找到一种更加高效的算法,否则要想实现性能的指数级增长通常是不太可能的

 

对代码优化而言,学习和使用查找和排序的最
优算法才是康庄大道。一个低效的查找或排序算法的例程可以完全占用一个程序的运行时
间。修改代码可以将程序运行时间减少一半。但是替换一种更优的算法后,数据集越大,

可以缩短的运行时间就越多。即使在一个只有一打数据的小数据集上,如果频繁查找数
据,最优的查找或排序算法也可以帮你节省很多时间

3-使用更好的库

C++ 编译器提供的标准 C++ 模板库和运行时库必须是可维护的、全面的和非常健壮的。令
开发人员吃惊的是,我们无需对这些库进行调优。可能更令人吃惊的是,虽然 C++ 已经发
明出来 30 年多了,商业 C++ 编译器的库仍然有 bug,而且可能不遵循现在的 C++ 标准,
甚至不遵循编译器发布时的标准。这使得测量和推荐优化方法的任务变得非常复杂,也使
得开发人员认为没有任何优化经验是可以移植的。

 

Boost Projecthttp://www.boost.org)和 Google Codehttps://code.google.com)等公开了很
多可供使用的库,其中有一些用于 I/O、窗口、处理字符串(请参见 4.3.3 节)和并发(请
参见 12.5 节)的库。它们虽然不是标准库的替代品,却可以帮助我们改善性能和加入新的
特性。这些库在设计上的权衡与标准库不同,从而获得了处理速度上的提升。

4-减少内存分配和复制

减少对内存管理器的调用是一种非常有效的优化手段,以至于开发人员只要掌握了这一个
技巧就可以变为成功的性能优化人员。绝大多数 C++ 语言特性的性能开销最多只是几个指
令,但是每次调用内存管理器的开销却是数千个指令。
由于字符串是许多 C++ 程序中非常重要(和性能开销大)的部分。
对缓存复制函数的一次调用也可能消耗数千个 CPU 周期。因此,很明显减少复制是一种
提高代码运行速度的优化方式。大量复制的发生都与内存分配有关,所以修改一处往往也
会消灭另一处。其他可能会发生复制的热点代码是构造函数和赋值运算符以及输入输出。

5-移除计算

除了内存分配和函数调用外,单条 C++ 语句的性能开销通常都很小。但是如果在循环中
执行 100 万次这条语句,或是每次程序处理事件时都执行这条语句,那么这就是个大问题
了。绝大多数程序都会有一个或多个主要的事件处理循环和一个或多个处理字符的函数。
找出并优化这些循环几乎总是可以让性能优化硕果累累。

以性能优化为主题的文献介绍了许多高效地使用单独的 C++ 语句的技巧。许多程序员相信
这些诀窍是优化的基础。这种看法的问题在于,除非一段代码真的是热点代码(被频繁地
执行的代码),否则从中移除一两句内存访问对程序的整体性能不会有什么改善。

现代 C++ 编译器在进行这些局部改善方面也做得非常优秀了。因此,开发人员不
应当有强迫症,将大段代码中的出现的 i++ 都换成 ++i,或是展开所有的循环,不遗余力
地向每位同事讲解什么是达夫设备Duffs Device8 以及它的优点

6-使用更好的数据结构

选择最合适的数据结构对性能有着深刻的影响,因为插入、迭代、排序和检索元素的算法
的运行时开销取决于数据结构。除此之外,不同的数据结构在使用内存管理器的方式上也
有所不同。另一个原因是数据结构可能有也可能没有优秀的缓存本地化。

7-提高并发性

大多数程序都需要等待发生在物理现实世界中的无聊、慢吞吞的活动完成。它们必须等待
文件从硬盘上读取完成、网页从互联中返回或者是用户的手指缓慢地按下键盘。任何时
候,如果一个程序的处理进度因需要等待这些事件被暂停,而没有利用这些时间进行其他
处理,都是一种浪费。
现代计算机都可以使用多个处理核心来执行指令。如果一项工作被分给几个处理器执行,
那么它可以更快地执行完毕。
伴随并发执行而来的是用于同步并发线程让它们可以共享数据的工具。有人可以用好这些
工具,有人则用不好。

8-优化内存管理

内存管理器作为 C++ 运行时库中的一部分,管理着动态内存分配。它在许多 C++ 程序中
都会被频繁地执行。C++ 确实为内存管理提供了丰富的 API,虽然多数开发人员都从来没
有使用过。