[NIO]从300万到700万——dawn的协程优化

来源:互联网 发布:qc归属地 数据库 2016 编辑:程序博客网 时间:2024/04/29 22:11

dawn的协程库,使用的是kilim,不过已经远非kilim的原有代码,主要保留了协程的两个基本原语,再往上层,已经全部被替换了。


协程库,我学习过boost asio中的协程,也在我的机器上测试过单纯上下文切换的速度。这个速度在不同的机器之间没有可比性,因为彼此的cpu可能不同。但是在同一台机器上的不同库的对比,具有一定的参照性。


我记得,当时asio协程单线程情况下,协程切换的最高持续吞吐量大概是400万次每秒。

我当时是准备使用kilim,所以在同一时间也测试了kilim,我记得当时测试出来的持续吞吐量大约是260万次左右,当时稍微有点失望,不过拿asio参考的话,也达到了50%以上,所以,也就采用了kilim。


在前一段时间写dawn的时候,我专门优化过协程这块,最开始用的是红黑树做的定时器,跑的最大持续吞吐量大概是360-380万每秒。我怀疑是红黑树在不稳定的情况下发生了过多的翻转,导致了额外的开销。

于是,第二天,写了一个时间轮,换上去之后,不停的调整参数,测试吞吐量,发现还是380万左右。无论怎么调,都上不去。用jprofiler检测,看不出来明显的毛病,当时给我的感觉就是慢在内存的访问上,因为我的时间轮的每个tick用的都是链表。我下意思里觉得是慢在这,不过这已经是最简单的链表了,还能怎么优化?

就这样,我暂停了优化,全部精力投入了工作以及dawn的完善以及bug修改。


两周后的今天,早上醒来后,我躺在床上,就瞎琢磨了一下,就想到了这个问题,突然想,如果把tick上的链表换成循环队列呢?试试,立马起床,写了一个循环队列,为了避免循环队列溢出,我在循环队列的内部加上了链表,把超出循环队列容量的元素放入链表。我把循环队列的大小开到了10万。用循环队列代替了链表,开启测试用例,这次居然能跑到560万次每秒了,说明思路对了。我就调了调参数,大概把循环队列的大小设置为5万的时候,平衡性最好,吞吐量大约是600万每秒。看看时间,也写了将近一个小时了,于是我又躺着看了会新闻。

觉得这个循环队列+链表的方式还不够好,因为循环队列满的时候会启用链表,加大了开销,反而会在繁忙的时候降低吞吐量。如果只用循环队列而不用链表,又怕会溢出。突然,我想到,如果把链表的每个节点扩大点扩展成数组,不就结了。

立马动手,写了一个LinkedArrayList,数组链表,这样就不怕溢出了,也会保持很高的性能。换掉刚才的循环队列,运行测试用例,不出意外,第一次就跑到了600多万,经过10多分钟的参数调整,最后,把数组长度定为5000,单个线程,20万协程,协程上下文切换达到700多万次每秒。


达到这个速度,还是很超出我的预期的,我最开始觉得能到500多万就满足了,最终到了700多万。

于是我又测试了一下定时任务,竟然执行了到了1100万次每秒,以往最好的历史记录大约是900多万,这足以说明,这次改进降低了协程调度的成本。


其实调度速度的快慢并没有决定意义,但是,这可以给上层应用一个更好的基础,让出更多的cpu资源给应用程序,或者是让应用可以使用更多的协程,让系统繁忙的时候运行的更有效率。


好吧,先调到这里吧,到这里,已经暂时达到我现有水平的极限了。

0 0
原创粉丝点击