Go语言性能优化实战

过早优化是万恶之源,这里都是黑魔法,不是性能瓶颈慎用

  • 根据pprof数据优化
  • 尽量避免GC,所以要避免创建过多的对象,也可以通过设置 GOGC 环境变量来增加触发GC的阈值,缺点是费内存。
  • 尽量的复用已经创建的对象,其中就包括如果可以的话,预先创建好对象。参考: https://golang.org/pkg/sync/#Pool
  • 避免锁,可以考虑 CAS。https://golang.org/pkg/sync/atomic/
  • 如果可以的话,用struct代替map。一个简单的例子就可以说明:

    package main
    
    type structDemoStruct struct {
    	First int
    }
    
    var (
    	mapDemo    = make(map[int]int, 1)
    	structDemo = structDemoStruct{}
    )
    
    func mapIncr() {
    	mapDemo[1]++
    }
    
    func structIncr() {
    	structDemo.First++
    }
    
    package main
    
    import (
    	"testing"
    )
    
    func BenchmarkMap(b *testing.B) {
    	for i := 0; i < b.N; i++ {
    		mapIncr()
    	}
    }
    
    func BenchmarkStruct(b *testing.B) {
    	for i := 0; i < b.N; i++ {
    		structIncr()
    	}
    }
    

测试结果:

$ go test -bench .
goos: linux
goarch: amd64
BenchmarkMap-4      	100000000	        20.5 ns/op
BenchmarkStruct-4   	1000000000	         2.02 ns/op
PASS
ok  	_/home/jiajun/tests	4.299s
  • defer 虽然好用,但是也会带来性能损伤。如果是高并发的服务,可能要注意一下
  • time.Now 比你想象中的慢,如果时间精确度不高,可以自己实现一个粗略的时钟
  • []byte和string转换比你想象中的慢,而且不能愉快的重复利用
  • 减少锁的使用,缩小临界区
  • 如果是CPU Bound的话,可以考虑设置 GOGC 来用内存换CPU时间

更多文章
  • Redis源码阅读:AOF重写
  • Redis源码阅读:AOF持久化
  • Redis源码阅读:key是怎么过期的
  • Redis源码阅读:字典是怎么实现的
  • Redis源码阅读:执行命令
  • Redis源码阅读:启动过程
  • WAL(Write-ahead logging)的套路
  • 搞定CORS问题
  • 如何定位程序问题所在
  • 设计一个IM归档系统
  • logrotate read only filesystem问题
  • Golang GIN写单测时,愉快的使用返回值
  • Python Queue源码分析
  • Go里优雅的使用全局配置
  • Golang sync.Map源码分析