前言
提高程序运行速度一直都是孜孜不倦的话题,的确,在飞速发展的今天,时间就是金钱。
更好的算法
提高速度,最核心的还是设计好的算法,好的算法能巧妙地利用更少的步数来达到相同的效果。如果程序的速度不理想,是时候考虑设计好的数据结构和优化计算流程了。
算法的基本目的是让一些基本操作(插入,删除,查找)达到更快的速度或使用更少的内存。
熟悉并测试每种数据结构及算法的性能,在日常开发中根据具体的操作类型和硬件条件,选择合适的数据结构并运用算法来提高处理效率。
数据结构还是第一位的,是运用算法的先决条件,抛开数据结构聊算法确实是耍流氓。
缓冲
把一个缓冲为一批,然后分批处理。这是一个比较常见的优化方式,不管是日常生活中,还是数据传输过程中,都用到这种思想。
sql
数据库在增删改的时候,如果每条数据请求一次数据库,就会浪费太多时间在网络传输上,因此可以把多条sql一起提交给数据库执行。
数据库连接字符串需要配置rewriteBatchedStatements=true和allowMultiQueries=true
redis
redis也有类似的功能,叫做pipeline,可以把多个命令打包给服务器一起执行,然后得到多个命令的应答。
批量
批量场景是相对于单个场景的,批量和缓冲类似,区别是缓冲的单个命令都是独立的,而批量是命令的参数是多个,实际只有一条命令;所以,批量相较于缓冲,能提供更好的原子性。
mysql
mysql的in
操作,以集合作为参数,批量执行;
redis
m开头的一些命令,比如mget
,mset
,也是批量场景。
规避无用IO
有些io操作是可以避免的,其中零拷贝技术就是一个例子。避免了在多个上下文进行不必要的数据拷贝,从而规避了一些无用io。
缓存
选择合适数据结构来存储数据,并且在需要的时候直接读取缓存,而不是重新计算或者读取数据库。目前最最流行的缓存系统是redis,redis最大的优势提供了丰富的数据结构,开箱即用;并且每种数据结构采用了特殊的内存优化算法,大大提高了内存使用率。
并行
如果一个任务的时间较长,并且有多个这样的任务,可以利用多个处理器的特点,开启多个线程,并行地执行这些任务,完成多个任务(取决于cpu核心数)只花一倍的时间。
如果一个任务需要花费的必要时间(t)比较长,可以多开几个任务(n)同时进行,以达到一个满意的速率(v),即nt变为t。
平均分配每个线程的任务量
并行执行任务时,最好保证每个线程的任务量相等,这样,每个线程执行完任务的时间相等,可以几乎同时完成任务。开启并行任务时,可以把所有任务,按照需要开启的并行数parallel
,平均地分配到每个线程,然后在每个线程中遍历任务即可。
taskPerThread=total%parallel==0?total/parallel:total/parallel+1
IO密集
如果是IO密集型任务,线程大部分时间在等待IO,没有过多消耗CPU资源(适合伪并行
),此时可以考虑开启的并行数parallel
(取决于内存大小)多一些,可以比可用核心数
大,甚至多倍(1~可用核心数
倍)。
CPU密集
如果是CPU密集型任务,线程主要使用CPU资源,CPU一直在忙,伪并行
意义不大,所以开启的并行数parallel
等于可用核心数
就OK了。
在资源充足(不会OOM)的情况下,要开启的线程数取决于任务的io时间
ti
和cpu时间tc
的比重,比如一个任务1s的时间内,200ms在进行cpu操作,800ms在等待io,那么,完全可以多开800/200=4个线程去等待io,让cpu一刻也闲不下来。
多节点
使用多台机器同时处理数据,弥补单台计算机的资源不足。现在比较流行的大数据框架,比如flink,能够生成任务的物理拓扑图,自动启动容器计算任务,充分利用了多台机器的资源。