你肯定习惯通过 goroutine 同时运行函数,觉得很酷,对吧?但实际上太多 goroutine 会拖慢运行速度,每个 goroutine 都会占用一定内存,如果程序运行了数百万个 goroutine,就会增加很多内存。
避免以下做法:
for_,item:=range bigList{goprocess(item)}
试着用信号量(semaphore)进行限制:
sem:=make(chan struct{},100)// 限制 100 个 goroutinesfor_,item:=range bigList{sem<-struct{}{}gofunc(i Item){deferfunc(){<-sem}()process(i)}(item)
我曾经做过航班搜索项目,该项目具有数百万的搜索规模。我们在很多地方都添加了 goroutine,试图对其进行优化。这时我才意识到 goroutine 会占用大量内存。我们需要持续监控每个点上运行的 goroutine 的数量,并需要建立某种机制,根据性能要求对其进行调整。
channel 非常适合用于程序之间通信,但也可能很棘手。不带缓冲的 channel 会导致程序在意想不到的时候阻塞。
避免以下做法:
ch:=make(chan int)
在需要的时候使用带缓冲的 channel:
ch:=make(chan int,100)// 缓冲大小为 100
带缓冲的 channel 可确保发送方在接收方尚未准备好接受任何数据的情况下不会被卡住,可以帮助我们简化流程,尤其是在处理大规模事务时,通道可能会非常繁忙。
全局变量初看似乎很简单,但可能会带来很多问题。全局变量会让人很难跟踪变化的内容,并可能导致错误。
避免以下做法:
varcounter int funcincrement(){counter++}
传递变量:
funcincrement(counter int)int{returncounter+1}counter:=0counter=increment(counter)
曾经看到过遍布全局变量的代码,调试时完全是一场噩梦。保持局部化会让代码更简洁、更快速。
切片是 Golang 中使用最多的数据结构之一,因此我们有责任明智的使用。一不小心,就可能会在切片中拷贝更多数据。
避免不必要的拷贝:
// 不好: 创建新切片newSlice:=make([]int,len(oldSlice))copy(newSlice,oldSlice)// 更好: 只使用原始切片newSlice:=oldSlice[:]
此外,在对切片添加数据时,如果知道容量会有多大,请考虑预先分配容量。
预先分配容量:
s:=make([]int,0,100)// 容量为 100
这有助于避免多次分配内存,加快速度。
需要采取某种机制来检查代码与模块的效率,Go 内置工具可以帮助查看程序把时间花在了哪些方面。
使用分析工具(profiler):
import("runtime/pprof""os")funcmain(){f,_:=os.Create("cpu.prof")pprof.StartCPUProfile(f)defer pprof.StopCPUProfile()// 业务代码}
运行分析工具后,可能会发现某个你认为很快的函数实际上拖慢了速度。修复后,程序可以运行得更快了。
Go 有一些漂亮的库,而我犯的一个错误就是在项目中引入了很多 Go 已经提供的功能。强烈建议你在编写代码之前,先检查一下 Go 是否已经提供了相应功能。
避免编写自己的排序功能:
funcmySort(data[]int){// 自定义排序}
使用内置排序软件包:
import"sort"sort.Ints(data)
以前我经常重新发明轮子,但现在更多依赖标准库,这样代码可以更简短,通常也更快。
分配内存需要时间。如果在短时间内创建许多临时对象,考虑到创建对象所耗费的时间,很可能会影响性能。
尽可能复用对象:
varbuffer bytes.Bufferfori:=0;i<1000;i++{buffer.Reset()buffer.WriteString("Some data")process(buffer.Bytes())}
通过重复使用 buffer,可以避免每次都分配新的内存,这个技巧可以加快运行多次的循环速度。
Go 的每个新版本都会对性能进行改进,总是使用最新的 Go 版本,就能免费获得这些优势。
因为更新看起来会很麻烦,因此很多人会一直使用旧版本,但升级后很有可能会发现程序在不修改任何代码的情况下运行得更快了!
这些是多年来积累的一些小技巧。每个项目都有所不同,请确保解决方案确实能够解决你的问题,而每当面临某种性能瓶颈时,请注意上述提到的方面。
最后,在修改代码后,一定要记得对代码进行测试和性能分析。有时,我们认为的优化可能达不到预期效果。