一次性能优化

1、先说背景

      导入一个文件,文件内容为20万个手机号码,将这20万个手机号码插入到数据库中。

      整个过程:a.解析文件;b.读取每行数据;c.读取到的行数据放入一个LinkedList中;d.遍历这个LinkedList,把通过校验的元素放入新的一个LinkedList中;e.遍历这个新的LInkedList,逐个元素进行插入数据库操作

     一次操作耗时约2~3分钟

2、寻找问题

     通过对过程的概述,可以发现有3个显著的问题,a.用了2个LinkedList(空间消耗);b.遍历了2次LinkedList(时间消耗);c.执行了20万次的数据库插入操作(IO消耗)

3、产生问题的原因

     空间消耗虽然没有对总耗时造成多大的影响,但是考虑到内存消耗情况,也是应当进行解决的。

     2次遍历的时间消耗,跟进去看代码发现遍历的时候,使用的是for(int i=0;i<list.size();i++),然而,使用的list却是一个LinkedList,通过这种方式来进行遍历的话,其时间复杂度为 O(N²),这就是为什么会慢的原因了。

     插入数据库的IO消耗,在遍历的时候(依旧使用的是for(int i=0;i<list.size();i++)进行遍历的),对每个从list中取到的数据进行insert()操作,每次操作都会伴随着 a.获取连接;b.开启事务;c.执行插入操作;d.提交事务;e.关闭连接 等一系列的数据库IO操作,然后这种系列的操作还反复执行20万次,这样必然会变慢。

4、解决方法

     空间消耗,在读取文件的时候,就对读取到的行数据进行处理,将符合规则的数据存入list中,这样不仅可以减少一个list,还可以减少一次list的遍历。

     时间消耗,遍历方式进行一种改变,将其变为for-each的方式,或者在选择容器时,就使用ArrayList来代替LinkedList,这2种修改的方式都可以让其在时间复杂度上为O(1)。

     IO消耗,每次插入一条数据,这样必然是不可取的,将其从单条插入改为批量进行插入,减少数据库的IO次数,这样IO次数越少,时间消耗上面就会降低。

5、探究解决问题的背后

     把LinkedList变成ArrayList

     由于是数组了,根据寻址公式,可以马上获取到结果,时间复杂度上为O(1),但是也是由于是数组,添加时就会增长,每次扩容时就会产生一整块一整块的垃圾在内存中,当年轻代满了,MinorGC还没有触发时,直接进入老年代,在某种极端情况下,老年代碎片化严重,没有那么大的一整块内存空间分配时,触发Full GC,垃圾回收器如果是用的默认的Parallel Old,其特点是并发回收垃圾,但是会停止工作线程,造成系统卡顿,严重时这个卡顿效果就会持续很长一段时间;如果使用的是CMS,垃圾回收时,工作线程也是可以继续工作的,但是遇到极坏的情况下,CMS无法完成时,会调用Serial Old来进行处理,由于Serial Old的特性是单线程的,并且回收时也是会停止工作线程的,造成的卡顿效果将大大的延长。

     把for循环改为forEach

     通过迭代器来遍历,迭代器中存储着后续元素的索引,在时间复杂度上为O(1)。LinkedList是一个双向链表,会多存储2个前驱和后驱的指针,内存占用上来说,是比ArrayList多了不少,但是它不需要扩容、不需要连续的内存空间,扩容会带来垃圾,如果在MinorGC触发前,程序已经执行完成了,那么,LinkedList所造成的内存消耗,是否又比ArrayList少了一些呢?

     IO消耗问题

     执行了20万次的insert操作,需要频繁获取Session,获取连接,然后每插入一条就要提交一次,数据库又是基于文件系统的,每一次insert操作,就是要向文件中写入数据,都会进行一次用户态到内核态的切换,每次切换都会执行中断指令,等到内核态切换为用户态时再从中断服务中恢复用户进程。程序和数据库建立连接是一次IO操作,数据库再和操作系统交互又是一次IO,然后再乘以20万次,所以会慢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值