代码优化
C++性能优化指南
【权衡利弊】
权衡简单性、安全性、获得的性能提升效果
【过程】
1)观察了解程序运行结果及代码
2)可测试的预测优化方案
3)实现优化
4)测试评估
总结:优化是实验而非直觉
【优化方向】
通过调整达到十几倍的效率提高是不可能的,通过修改算法和数据结构是可能。
【优化过程注意项】
1)找出性能问题出在哪,在寻找优化方法进行优化
2)尝试自己编写几次最优查找和排序,有助于自己编写代码时写出更优的算法(因为你离不开查找排序)
3)常识可能是性能改善的最大敌人,常识的“解毒剂”是实验形式的科学方法
4)如果运行速度只提高1%是不值得冒险取修改代码的,因为修改代码可能会会引入bug
【用好的编译器并用好编译器】
1)建议使用支持C++11的编译器,因为C++11实现了右值引用和移动语句
2)正确使用优化选项,可以让程序的运行速度提高数倍
【使用更好的算法】
1)选择一个最优算法对性能优化的效果最大
【使用更好的库】
1)选择可维护的全面的和非常健壮的库
2)善用开源库,它们很容易的整合至现有的工程中,并能够立即改善程序性能。
eg:Boost Project(http://www.boost.org)
Google Code (https://code.google.com)
【减少内存分配和复制】
开发人员只要掌握了这个技巧就可以变成成功的性能优化人员
【提高并发性】
【优化内存管理】
【小节】
1.使用更好的编译器,打开编译选项
2.使用最优算法
3.使用更好的库并用好库
4.减少内存分配
5.减少复制
6.移除计算
7.使用最优数据结构
8.提高并发
9.优化内存管理
【细节优化】
1)特别注意循环中不必要的语句删除
2)选择好的数据结构
干着软件开发,深受硬件设备痛苦中,在此批评王者荣耀,表扬QQ。王者荣耀直接变成云形式,当把用户承受的硬件痛苦转嫁到自己身上,也许才会考虑自身代码优化问题。
电脑系统在更新换代,处理器从单核到多核,从4核到8核。内存从4G到8G,16G,32G
确实越来越好看,却没有越来越顺畅。
///
【代码分析工具】
1)分析器:一般编译器都会有的分析工具
帮助你分析每行代码的访问量,每个函数的调用次数,函数累计执行时间
vs2008以上版本都带分析器
2)计时器:自己实现程序运行时间统计
【90/10规制】
定义:90%的时间在执行10%的代码
找到这个热点10%,就是性能优化的地方
【实验过程】
1)必须测量性能
2)做出可测性的预测并记录预测
3)记录代码修改
4)如果每次都记录实验内容,可快速重复实验
【string动态处理分配内存】
1)使用复合赋值避免临时字符串
string result;
eg: result += str, 代替 result = result + str. 因为C++11右值赋值可减少临时拷贝,性能相差13倍
2)提前分配内存,可提高20%的效率
result.reserve(s.length());
3)循环中使用迭代器,迭代器是指向字符缓冲区的简单指针,可以节省两次接引操作
for (auto it=s.begin(),end=s.end(); it != end; ++it)
4)使用append减少临时变量
result = result + s.substr(b,i-b) =》result.append(s, b, i-b)
5)减少常量字符转换成std::string
char const* MyClass::Name() const {
return “MyClass”;
}
char const* p = myInstance->Name(); // 没有转换
std::string s = myInstance->Name(); // 转换为’std::string’
std::cout << myInstance->Name(); // 没有转换
6)在循环外创建变量
for (auto& filename : namelist) {
std::string config;
ReadFileXML(filename, config);
ProcessXML(config);
}
config在循环末尾离开了它的作用域后,将会被销毁,它的存储
空间会被返回给内存管理器:
std::string config;
for (auto& filename : namelist) {
config.clear();
ReadFileXML(filename, config);
ProcessXML(config);
}
7)善用move
result = str
=> result = std::move(str)
【共享内存指针】
1)共享内存指数的开销是昂贵的
2)能用std::unique_ptr就不要用std::shared_ptr
3)用std::make_shared替代new
【减少不必要复制】
1)std::vector scalar_product(std::vector const& v, int c)
=》void scalar_product(std::vector const& v, int c, vector& result)
【移除循环不变性代码】
int c=10,j=10;
set ss{0,1,2,3};
int sum=0;
for(int i=0; i<ss.size(); ++i)
{
sum +=i+cj;
}
=>
int c=10,j=10;
set ss{0,1,2,3};
int sum=0;
int temp = cj;
int nSize = ss.size();
for(int i=0; i<nSize; ++i)
{
sum +=i+temp;
}
【将常量组合在一起】
支持c++11以上的编译器,编译器可以帮们计算常量表达式
eg:
seconds = 24 * 60 * 60 * days; 或 seconds = days * (24 * 60 * 60);
编译器优化后:
seconds = 86400 * days;
如果是:seconds = 24 * days * 60 * 60,编译器只能在运行时进行乘法计算了。
【使用更高效的运算符】
eg:
1)x4 换成 x<<2 (注:x二进制像左移动两位)
2)用位移运算和加法运算替代乘法 x9 换成 (x<<3)+x
3)用整数代替浮点数
4)用switch代替if-else if
5) double可能比float快
【多线程优化】
1)用std::async替代std::thread
2)减少静态成员变量,因为程序会先对静态成员变量初始化
3)限制并发线程数量,应当是可运行的线程的数量少于或等于处理器核心的数量
4) 多线程中减少资源竞争,资源竞争导致无法并发,影响效率
解决方法:复制资源、分隔资源、细粒度锁(多个互斥量)
5)建议使用并发库,
eg:Boost.Thread(http://www.boost.org/doc/libs/1_60_0/doc/html/thread.html)
Boost.Coroutine(http://www.boost.org/doc/libs/1_60_0/libs/coroutine/doc/html/index.html)