【架构师之路 四】需要掌握的技能点---架构性能优化

涉及到性能优化的东西,我总结以下主要其实是三个方面:

1,充分利用好缓存

2,数据和处理可以提前预测

3,以空间换取时间

4,延迟使用,只有真正使用的时候才进行计算

代码级别

关联代码优化

如果代码段A的修改会导致断码段B需要跟着修改或者功能发生变化,则称B是A的关联代码关联代码可能是相互的,也可能是单向的

Cache对齐

CPU高速缓存性能优化

http://blog.csdn.net/zhang_shuai_2011/article/details/38119657

分支预测

CPU的性能优化关联,分支预测(Branch Prediction):从P5时***始的一种先进的,解决处理分支指令(if-then-else)导致流水线失败的数据处理方法,由CPU来判断程序分支的进行方向,能够加快运算速度。

https://segmentfault.com/a/1190000006889989

Copy on Write

浅拷贝,只复制引用,而不复制值,只有在用到的时候才加载对象

https://www.jianshu.com/p/b5b95a710fec

内联优化

以空间换时间,提高函数调用速度

http://blog.csdn.net/wenqian1991/article/details/17201555

工具优化

OProfile

OProfile是Linux内核支持的一种性能分析机制,是用于 Linux 评测和性能监控的工具。oprofile 是 Linux 平台上的一个功能强大的性能分析工具, 支持两种采样(sampling)方式:基于事件的采样(event based)和基于时间的采样(time based)。
基于事件的采样是oprofile只记录特定事件(比如L2 cache miss)的发生次数,当达到用户设定的 定值时oprofile 就记录一下(采一个样)。这种方式需要CPU 内部有性能计数器(performace counter)。

基于时间的采样是oprofile 借助OS 时钟中断的机制,每个时钟中断 oprofile 都会记录一次(采一次样)。引入的目的在于,提供对没有性能计数器 CPU 的支持。其精度相对于基于事件的采样要低。因为要借助 OS 时钟中断的支持,对禁用中断的代码oprofile不能对其进行分析。

oprofile 在Linux 上分两部分,一个是内核模块(oprofile.ko),一个为用户空间的守护进程(oprofiled)。前者负责访问性能计数器或者注册基于时间采样的函数(使用register_timer_hook注册之,使时钟中断处理程序最后执行profile_tick 时可以访问之),并采样置于内核的缓冲区内。后者在后台运行,负责从内核空间收集数据,写入文件。

Gprof

gprof,打印出程序运行中各个函数消耗的时间,可以帮助程序员找出众多函数中耗时最多的函数。 有了函数的调用关系,这会让开发人员大大提高工作效率,不用费心地去一点点找出程序的运行流程,这对小程序来说可能效果不是很明显,但对于有几万,几十万代码量的工程来说,效率是毋庸置疑的!而且这个功能对于维护旧代码或者是分析Open Source来说那是相当诱人的,有了调用图,对程序的运行框架也就有了一个大体了解,知道了程序的”骨架”,分析它也就不会再那么茫然,尤其是对自己不熟悉的代码和Open Source。费话不多说了,让我们开始我们的分析之旅吧!

JDK工具

JVM的性能调优工具,目前暂不常用

https://www.csdn.net/article/2014-11-20/2822750-5-JDK-To

系统优化

Cache

cache高速缓冲存储器一种特殊的存储器子系统,其中复制了频繁使用的数据以利于快速访问。存储器的高速缓冲存储器存储了频繁访问的RAM位置的内容及这些数据项的存储地址。当处理器引用存储器中的某地址时,高速缓冲存储器便检查是否存有该地址。如果存有该地址,则将数据返回处理器;如果没有保存该地址,则进行常规的存储器访问。因为高速缓冲存储器总是比主RAM存储器速度快,所以当RAM的访问速度低于微处理器的速度时,常使用高速缓冲存储器。

延迟计算(与浅拷贝类似)

延迟求值特别用于函数式编程语言中。在使用延迟求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值,也就是说,语句如 x:=expression; (把一个表达式的结果赋值给一个变量)明显的调用这个表达式被计算并把结果放置到 x 中,但是先不管实际在 x 中的是什么,直到通过后面的表达式中到 x 的引用而有了对它的值的需求的时候,而后面表达式自身的求值也可以被延迟,最终为了生成让外界看到的某个符号而计算这个快速增长的依赖树。
某些编程语言缺省延迟表达式的求值,另一些提供函数或特殊语法来延迟求值。在 Miranda 和 Haskell 中,缺省延迟函数实际参数的求值。在很多其他语言中,可以使用特殊语法明确悬置计算来延迟求值(比如 Scheme 的 “delay” 或 “force”),更一般的通过把一个表达式包装在 thunk 中。表示这种明确延迟求值的对象叫做预期或承诺。
延迟求值的一个好处是能够建立可计算的无限列表而没有妨碍计算的无限循环或大小问题。例如,可以建立生成无限斐波那契数列表的的函数(经常叫做“流”)。第n 个斐波那契数的计算仅是从这个无限列表上提取出这个元素,它只强迫这个列表的前 n 个成员的计算。

数据预读

Prefetch指在处理器进行运算时,提前通知存储器子系统将运算所需要的数据准备好,当处理器需要这些数据时,可以直接从这些预读缓冲中,通常指Cache,获得这些数据,不必再次读取存储器,从而实现了存储器访问与运算并行,隐藏了存储器的访问延时。

http://blog.csdn.net/sailing_w/article/details/55003980

异步

异步的另外一种含义是计算机多线程的异步处理。与同步处理相对,异步处理不用阻塞当前线程来等待处理完成,而是允许后续操作,直至其它线程将处理完成,并回调通知此线程。

轮询与通知

通知实现的方法,按我的理解和linux下很多程序实现的方法如下:
程序再起socket的时候,设定socket为阻塞的方式,也就是说socket监听端口的时候,如果没有数据,监听进程就是挂起休眠起来,实际上,这个时候程序已经休眠,不占用cpu资源,也就谈不上费电,当基带从空口获取到一个数据片的时候, 底层会触发一个中断给cpu,cpu判断这个中断类型,如果是ip包,cpu会吧数据传给tcp/ip协议栈,协议栈根据socket注册情况,唤醒相应的程序,这个时候就可以切换到真正处理的app里面去了,这样实现起来省电,高效,但是ios悲催的内存大小和进程调度方式,可能会导致休眠的程序丢失一部分进程资源,导致切换会app的时候,可能还需要重新登陆==一系列动作,这样造成用户体验不好,但是我觉得这个机制是非常适合手持设备的,希望将来ios能解决进程切换的问题。这就是为什么有个兄弟说一个ios设备给另外一个ios设备发消息,可能再1秒以内能收到的原因。因为全部都是主动触发的方式,相当于多米诺骨牌一样,自然速度会很快

所谓轮询的方式,
哪就是很多现在pc和android上实现的方法,注册socket为非阻塞的方式,也就是说socket监听端口的时候,如果没有数据,监听进程就会放过这次监听,使用timer/sleep 固定时间,然后到一个门限的时候,比如说1秒/30秒的时候,主动向server发送查询的数据包,server查询结果,然后返回给设备,设备就知道这个查询时间片内有没有本程序的数据,这样实现起来费电,复杂,但是由于android使用linux进程调度算法,最终结果看起来也是可以接受的。
简而言之:通知是被动,轮询是主动,一个不开,直到被触发才打开,另一个一直开着

内存池

Memory Pool)是一种内存分配方式。通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。

内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。

模块化

模块化设计,简单地说就是程序的编写不是开始就逐条录入计算机语句和指令,而是首先用主程序、子程序、子过程等框架把软件的主要结构和流程描述出来,并定义和调试好各个框架之间的输入、输出链接关系。逐步求精的结果是得到一系列以功能块为单位的算法描述。以功能块为单位进行程序设计,实现其求解算法的方法称为模块化。模块化的目的是为了降低程序复杂度,使程序设计、调试和维护等操作简单化。

并发

并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。

全部评论

相关推荐

11-18 15:57
门头沟学院 Java
最终归宿是测开:这个重邮的大佬在重邮很有名的,他就喜欢打92的脸,越有人质疑他,他越觉得爽😂
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务