C++并发编程性能优化

来源:互联网 发布:东莞淘宝摄影 编辑:程序博客网 时间:2024/06/08 12:18
C++并发编程性能优化


笔者使用C++语言进行软件开发。最近的两年时间做了一些关于软件系统的性能优化方面的工作。总结了一些性能优化,尤其是并发方面的性能优化的可参考的思路。分类总结如下,可以作为关于这方面的参考。

应用程序的性能要求,一般主要分类为:CPU消耗型,内存消耗型,磁盘消耗型,网络消耗型。


做性能优化,可以从如下的思路入手,
(1)语言方面。
    语言方面包括语言的特性,语言的升级。主要指的是利用语言的语法规则,进行性能优化。
    就C++语言来讲,有如下特性可以利用:
    第一点可以利用引用或指针,来减少类的构造和析构。虽然说现在的CPU已经快的不行,但是频繁大量的构造和析构,往往有时候是在做无用功,本可以避免。构造析构不仅只是对象的创建和销毁,对于参数还要进行入栈出栈。如果对象含有内存、句柄等等的资源,那么对于资源的获取、访问与销毁,就要精心构造你的copy-constructor和operator=,否则就会引起内存问题。
    在C++98/03标准里,有左值引用可以利用来进行优化。
    在C++11标准里,引入了右值引用、move语义和forward完美转发的新特性,这些新特性的引入,主要的就是为了进行性能优化。
    随着C++11新特性的引入,早期C++的类的4大函数(即constructor,destructor,copy-constructor,operator=),也扩展编程了6大函数(新增的为带右值引用的copy-constructor和operator=)。
    
    第二点可以利用语言提供的原子操作,部分地代替锁来进行互斥。但是是否能够进行原子操作要依据它的规则。
    
(2)I/O方面。
    工作原因,笔者所经历的I/O方面的优化,主要集中在网络I/O上,网络I/O又主要是针对TCP进行的优化。TCP的传输优化,可以从互联网上找到非常多的资料,无外乎3个思路,使用异步I/O模型,修改TCP选项,使用更优的拥塞控制算法。
笔者之前给公司的一台java开发的媒体服务器做性能优化,应用协议是http,主要是想提高tps。该视频服务软件是第三方公司提供,我们使用它的sdk做二次开发,优化的方法是修改tcp选项。优化后,该sdk的tps从400~500,提高到1000以上。
关于tcp的拥塞控制算法,目前笔者所使用的较新的算法是google公司基于大数据统计而改进的BBR算法。
针对传输层的优化不一而足,除了上面提到的3个常规思路外,必要情况下,也可以考虑更换传输层协议。笔者所在团队之前做一款针对家用的监控摄像机时,曾考虑过使用tcp/udp之外的传输协议进行技术预研,后来由于公司政策方面一些原因没有推动落地。

(3)架构方面。
架构方面,引起并发性能的限制,可以说是最不容易进行重构优化的。因为架构的变动会引起连锁反应,除了耦合模块的修改外,功能测试、产品发布等都是需要提前做好沟通和会议安排的。笔者团队此前曾就一款C++开发的视频服务器做优化,也是针对http做tps优化,通过对架构进行调整,并附带有数据结构和锁的优化,tps从1000优化到7000。网络是千兆单网卡,7000tps当时是把带宽占用满了,基本也就接近于网络的负载极限。

架构方面的优化手段,诸如对内存数据库的使用,内存池的使用优化,线程池的使用和优化,等等。另外比较隐蔽的架构优化,包括数据结构的优化,业务模型的合理设计,等等。


(4)库方面。
库方面,其实主要说的就是开源库的选择。目前有一定热度、有名的开源库,基本都能够保证较为不错的性能。

作为一名C++开发者,笔者的最深体会是,C++是最容易引起开发者重新造轮子的语言。类型声明不一致,头疼;编码风格不一样,头疼;借口声明不统一,头疼;没有强大的基础库,有各种各样实现同样目的库,头疼......C++就是这样,要么是没有选择的痛苦,要么是选项太多的痛苦。


(5)业务和资源整合方面。
业务和资源整合方面的优化,其实并没有什么固定方法可以借鉴,因为业务是强依赖与开发者的思维方式和使用习惯的,业务也往往是用户、甲方的使用者提出来的。一般来讲,业务与资源整合往往会影响代码逻辑。这通常包括,
要尽量减小互斥锁的代码范围。范围越大,竞争条件在时间维度就越激烈。
避免死锁。
对于较少set、更多时候是get的变量,可使用读写锁。
使用条件变量减少频繁的轮训询问。
减少内存拷贝。(这一条也可归于I/O方面。)

进行软件性能优化的思路手段很多,绝对不可能一言以蔽之。具体的方法还需要开发人员多思考,多借鉴,多学习优秀经验。
下面对文章内提到的优化点进行汇总:
1、减小锁范围
2、避免死锁
3、使用读写锁
4、使用条件变量
5、使用原子操作
6、使用线程池
7、精心设计你的数据结构
8、使用内存池
9、减少内存拷贝
10、对你的业务流程进行优化
11、使用内存数据库
12、使用引用和指针代替值传参
13、减少对象的构造和析构次数
14、选择优秀的库
15、tcp优化,拥塞算法,NODELAY等
16、使用右值引用

17、优化你的领域模型



原创粉丝点击