Golang多协程版本性能变慢问题探讨
Golang多协程版本性能变慢问题探讨
我编写了一个生成曼德博集合图像的程序。
单协程版本大约需要20秒。
多协程版本大约需要30秒。
两者产生的结果完全相同。
在单协程版本中,我看到一个核心被完全占用;而在多协程版本中,所有核心都被完全占用。
我已经检查过,这不是垃圾回收(GC)的问题(使用 GODEBUG=gctrace=1 go run main.go),因为在初始化设置之后就没有垃圾产生了。
程序中没有使用 math.rand。
我应该从哪些方面着手,来找出它为什么没有运行得更快呢?
谢谢
嗯……又是一个先提问后找到答案的情况!(这个世界真奇妙!😊)
无论如何,我的答案是……
go run -race main.go
我之前有一个全局变量,它在实际的工作例程中统计迭代次数。移除这个变量后,使用多个goroutine的版本在4秒左右就完成了。太好了。
那么新的问题是……当Go编译器发现某些竞态条件时,它会默默地添加一些同步工作吗? 答案看起来显然是肯定的……但也许还有其他原因?
更多关于Golang多协程版本性能变慢问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
首先,需要检查是否存在竞态条件或锁竞争。可以使用 -race 标志运行程序来检测竞态条件:
go run -race main.go
如果检测到竞态条件,需要修复数据同步问题。
其次,检查是否因协程间任务分配不均导致负载不均衡。以下是一个简单的负载均衡示例,使用工作池模式:
package main
import (
"image"
"image/color"
"image/png"
"math/cmplx"
"os"
"runtime"
"sync"
)
func mandelbrot(z complex128) color.Color {
const iterations = 200
const contrast = 15
var v complex128
for n := uint8(0); n < iterations; n++ {
v = v*v + z
if cmplx.Abs(v) > 2 {
return color.Gray{255 - contrast*n}
}
}
return color.Black
}
func worker(jobs <-chan int, img *image.RGBA, wg *sync.WaitGroup) {
defer wg.Done()
for y := range jobs {
for x := 0; x < 1024; x++ {
zx := float64(x)/1024*3.5 - 2.5
zy := float64(y)/1024*3.5 - 1.75
img.Set(x, y, mandelbrot(complex(zx, zy)))
}
}
}
func main() {
const width, height = 1024, 1024
img := image.NewRGBA(image.Rect(0, 0, width, height))
numWorkers := runtime.NumCPU()
jobs := make(chan int, height)
var wg sync.WaitGroup
for w := 0; w < numWorkers; w++ {
wg.Add(1)
go worker(jobs, img, &wg)
}
for y := 0; y < height; y++ {
jobs <- y
}
close(jobs)
wg.Wait()
f, _ := os.Create("mandelbrot.png")
png.Encode(f, img)
}
第三,检查是否存在伪共享(false sharing)问题。如果多个协程频繁写入同一缓存行中的不同变量,会导致性能下降。可以使用填充(padding)来避免:
type PixelData struct {
R, G, B, A uint8
_padding [60]byte // 填充到64字节,避免伪共享
}
第四,使用性能分析工具定位瓶颈:
go test -bench=. -cpuprofile=cpu.prof
go tool pprof cpu.prof
在pprof中使用top、list命令查看热点函数。
第五,检查是否因协程创建过多导致调度开销。适当控制协程数量,通常与CPU核心数相同或稍多即可。
第六,确保没有不必要的内存分配。使用go build -gcflags '-m'检查逃逸分析,减少堆分配。
最后,检查算法本身是否有优化空间,例如使用SIMD指令或更高效的数学计算库。

