我正在针对我的 redigo 函数运行此测试,看看它是否支持大量并发写入,这是代码import ( "github.com/gomodule/redigo/redis" "log" "os")// Redis connection poolvar RedisPool *redis.Poolfunc InitPool() { RedisPool = &redis.Pool{ MaxIdle: 80, MaxActive: 12000, Dial: func() (redis.Conn, error) { conn, err := redis.Dial("tcp", "127.0.0.1:6379") if err != nil { log.Printf("ERROR: fail init redis: %s", err.Error()) os.Exit(1) } return conn, err }, }}func ClosePool() error { return RedisPool.Close()}func Set(key string, val string) error { // get conn and put back when exit from method conn := RedisPool.Get() defer conn.Close() _, err := conn.Do("SET", key, val) if err != nil { log.Printf("ERROR: fail set key %s, val %s, error %s", key, val, err.Error()) return err } return nil}func TestManySets(t *testing.T) { InitPool() defer ClosePool() var wg sync.WaitGroup numOfOperations := 1000 for i := 0; i < numOfOperations; i++ { wg.Add(1) go func() { err := Set("key", strconv.Itoa(i)) if err != nil { t.Errorf("error when setting key value: %s", err) } wg.Done() }() } wg.Wait() result, err := Get("key") if err != nil { t.Errorf("error when getting key value: %s", err) } t.Logf("result: %s", result)}当运行测试时,go test -run TestManySets /path/to/package -count 1 -v我遇到了很多EOF错误;当使用 运行测试时-race,即go test -race -run TestManySets /path/to/package -count 1 -v我检测到大量数据竞争,任何人都可以向我指出如何才能使事情正确?
1 回答
一只名叫tom的猫
TA贡献1906条经验 获得超3个赞
竞争是因为你的 for 循环正在更新,i而你的 goroutine 正在i同时读取。解决这个问题的一种方法是传递i给你的 goroutine 函数:
for i := 0; i < numOfOperations; i++ {
wg.Add(1)
go func(i int) { // <----------- CHANGE THIS
err := Set("key", strconv.Itoa(i))
if err != nil {
t.Errorf("error when setting key value: %s", err)
}
wg.Done()
}(i) // <----------- AND THIS
}
这样你就不再有一个闭包i,并且i你的 goroutine 函数内部是一个独特的值,可以在不受外部干扰的情况下读取(或写入)。
这还解决了竞争检测器找不到的另一个错误:在循环中for,重复使用递增的变量,这意味着您当前的版本实际上i在许多情况下无意中使用相同的值,并跳过其他值。
- 1 回答
- 0 关注
- 89 浏览
添加回答
举报
0/150
提交
取消