为了账号安全,请及时绑定邮箱和手机立即绑定

减少并发 Set 带来数据竞争

减少并发 Set 带来数据竞争

Go
拉莫斯之舞 2023-07-26 15:41:11
我正在针对我的 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条经验 获得超2个赞

竞争是因为你的 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在许多情况下无意中使用相同的值,并跳过其他值。


查看完整回答
反对 回复 2023-07-26
  • 1 回答
  • 0 关注
  • 57 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信