[转]Golang号称高并发,但高并发时性能不高

1.管道chan吞吐极限10,000,000,单次Put,Get耗时大约100ns/op,不管是采用单Go程,仍是多Go程并发(并发数:100, 10000, 100000),耗时均没有变化,Go内核这对chan进行优化。

并发

解决之道:在系统设计时,避免使用管道chan传递主业务数据,避免将业务流程处理流程分割到对个Go程中执行,这样作减小chan传输耗时,和Go程调度耗时,性能会有很大的提高。异步

案例分析:nsq和nats都是实时消息队列,nsq在客户端端和服务端大量使用chan转发消息,致使性能不佳,只有100,000/s;而nats服务端在分发消息流程中,没有使用chan,只在客户端接收时使用chan,性能可达到1,000,000/s。性能

2.互斥锁Mutex在单Go程时Lock,Unlock耗时大约20ns/op,可是采用多Go程时,性能急剧降低,并发越大耗时越长,在Go1.5并发数达到1024耗时900ns/op,Go1.6优化到300ns/op,究其缘由,是构建在CPU的原子操做之上,抢占过于频繁将致使,消耗大量CPU时钟,进而CPU多核没法并行。优化

解决之道:采用分区,将须要互斥保护的数据,分红多个固定分区(建议是2的整数倍,如256),访问时先定位分区(不互斥),这样就可下降多个Go程竞争1个数据分区的几率。设计

案例分析:Golang的Go程调度模块,在管理大量的Go程,使用的就是数据分区。队列

3.select异步操做在单管道时耗时120ns/op,可是随着管道数增长,性能线性降低,每增长1个管道增长100ns/op,究其缘由,slelect时当chan数超过1后,Go内部是建立一个Go程,有它每1ms轮训的方式检查每一个chan是否可用,而不是采用事件触发。事件

解决之道:在select中避免使用过多的管道chan分支,或者把没法用到的chan置为nil;解决select超时,避免使用单独的超时管道,应与数据返回管道共享。内存

案例分析:nsq和nats都是实时消息队列,因为nsq大量使用chan,这就必然致使大量使用select对多chan操做,结果是性能不高。资源

4.Go调度性能低下,当出现1,000,000Go程时,Go的调度器的性能急剧降低。消息队列

解决之道:避免动态建立Go程,服务端收到数据并处理的流程中,避免使用chan传递业务数据,这样会引发Go程调度。

案例分析:nsq和nats都是实时消息队列,因为nsq大量使用chan,这就必然致使在服务过程当中,引发Go调度,结果是性能不高。

5.defer性能不高,每次defer耗时100ns,,在一个func内连续出现屡次,性能消耗是100ns*n,累计出来浪费的cpu资源很大的。

解决之道:除了须要异常捕获时,必须使用defer;其它资源回收类defer,能够判断失败后,使用goto跳转到资源回收的代码区。

6.内存管理器性能低下,申请16字节的内存,单次消耗30ns,64字节单次消耗70ns,随着申请内存尺寸的增加,耗时会迅速增加。加上GC的性能在1.4, 1.5是都不高,直到1.6, 1.7才获得改善。

解决之道:建议使用pool,单次Put,Get的耗时大约在28ns,在并发状况下可达到18ns,比起每次建立,会节省不少的CPU时钟。

相关文章
相关标签/搜索