事情的起因是因为 自己之前的 记一次go项目协程泄露问题排查, 然后了解到了 goleak 这个项目,于是记录一下吧,方便之后写代码时可以提前预测。
首先准备环境
redisgo
redis可借助docker一键搭建
docker rm -f redis
docker run -itd -p 6379:6379 --name=redis redis:latest
更多的docker搭建可关注docker系列-脚本sh总结
编写代码
- 创建
go.mod文件
go mod init go_case
文件内容为
module go_case
go 1.22.6
require (
github.com/go-redis/redis v6.15.9+incompatible
go.uber.org/goleak v1.3.0
)
2. 创建 goleak_test.go 文件,并编写以下代码
package about_goroutine
import (
"fmt"
"github.com/go-redis/redis"
"go.uber.org/goleak"
"testing"
)
func TestGoRedisLeak(t *testing.T) {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
DB: 0,
})
defer client.Close()
pong, err := client.Ping().Result()
fmt.Println(pong, err)
}
然后就运行 TestGoRedisLeak 方法就可以了,最终会得到如下结果
为什么发生了协程泄露,主要原因就是因为 go-redis/redis v6.15.9+incompatible 版本代码
会导致当 client 退出时协程还没退出,因此可以试着调小一点 idleCheckFrequency,调整为 100ms(本文仅演示,生产环境不建议)
func TestGoRedisLeak(t *testing.T) {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
DB: 0,
IdleCheckFrequency: 100 * time.Millisecond, //新添加的参数
})
defer client.Close()
pong, err := client.Ping().Result()
fmt.Println(pong, err)
}
此时就会得到结果如下:
感觉该功能在每次编写go代码的时候还比较重要,避免协程泄露嘛。
更多使用方法可参考 goleak