Redigo并发集提供数据竞争

Redigo并发集提供数据竞争,go,concurrency,redigo,data-race,Go,Concurrency,Redigo,Data Race,我正在对我的redigo函数运行这个测试,看看它是否支持大规模并发写入,下面是代码 进口 github.com/gomodule/redigo/redis 日志 操作系统 //Redis连接池 var RedisPool*redis.Pool 函数初始化池{ RedisPool=&redis.Pool{ MaxIdle:80, MaxActive:12000, 拨号:func redis.Conn,错误{ conn,err:=redis.Dialtcp,127.0.0.1:6379 如果错误!=

我正在对我的redigo函数运行这个测试,看看它是否支持大规模并发写入,下面是代码

进口 github.com/gomodule/redigo/redis 日志 操作系统 //Redis连接池 var RedisPool*redis.Pool 函数初始化池{ RedisPool=&redis.Pool{ MaxIdle:80, MaxActive:12000, 拨号:func redis.Conn,错误{ conn,err:=redis.Dialtcp,127.0.0.1:6379 如果错误!=零{ log.PrintfERROR:初始化redis失败:%s,错误。错误 操作系统Exit1 } 返回控制,错误 }, } } func关闭池错误{ 返回池。关闭 } func Setkey字符串,val字符串错误{ //获取conn并在退出方法时放回 conn:=RedisPool.Get 延迟连接关闭 _,err:=conn.DoSET,key,val 如果错误!=零{ log.PrintfERROR:设置密钥%s失败,val%s,错误%s,密钥,val,错误。错误 返回错误 } 归零 } func TestManySetst*testing.T{ 初始化池 延迟关闭池 var wg sync.WaitGroup numOfOperations:=1000 对于i:=0;i 当运行带有-race的测试时,即go-test-race-run-TestManySets/path/to/package-count 1-v,我检测到了大量的数据竞争,任何人都可以向我指出如何使事情变得正确

下面是数据竞赛日志:

ycx@DESKTOP-NBD349L:/mnt/c/Users/robbi/Projects/GoGameServer$go test-race-runtestmanysets visiontech.com/adapter-count 1-v ==运行TestManySets ================== 警告:数据竞争 goroutine 7在0x00c00009ab10处读取: visiontech.com/adapter.TestManySets.func1 /home/ycx/Projects/GoGameServer/src/visiontech.com/adapter/redis_test.go:48+0x3c goroutine 6在0x00c00009ab10的上一次写入: visiontech.com/adapter.TestManySets /home/ycx/Projects/GoGameServer/src/visiontech.com/adapter/redis_test.go:45+0x14c 特鲁纳先生 /usr/local/go/src/testing/testing.go:865+0x163 Goroutine 7正在运行,创建于: visiontech.com/adapter.TestManySets /home/ycx/Projects/GoGameServer/src/visiontech.com/adapter/redis_test.go:47+0x128 特鲁纳先生 /usr/local/go/src/testing/testing.go:865+0x163 Goroutine 6正在运行,创建于: 测试。*T.Run /usr/local/go/src/testing/testing.go:916+0x65a testing.runTests.func1 /usr/local/go/src/testing/testing.go:1157+0xa8 特鲁纳先生 /usr/local/go/src/testing/testing.go:865+0x163 testing.runTests /usr/local/go/src/testing/testing.go:1155+0x523 测试。*M.Run /usr/local/go/src/testing/testing.go:1072+0x2eb 梅因,梅因 _testmain.go:62+0x222 ================== --失败:TestManySets 10.08s redis_测试。开始:62:结果:1000 测试。go:809:在测试执行期间检测到竞争 失败 失败visiontech.com/adapter 10.098s ycx@DESKTOP-NBD349L:/mnt/c/Users/robbi/Projects/GoGameServer$
redis_test.go第47行是上面代码中的集合发生的地方。

竞争是因为for循环正在更新i,而goroutines正在同时读取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上的闭包,goroutine函数中的i是一个独特的值,可以在没有外部干扰的情况下读取或写入


这还解决了另一个缺陷,即竞争检测器无法发现的缺陷:在for循环中,递增的变量被重新使用,这意味着您当前的版本实际上在许多情况下无意中使用了相同的i值,并且跳过了其他情况。有关详细信息,请参阅。

您必须共享数据竞争检测输出,以便我们可以尝试进一步帮助您。当您获得数据竞争时,输出会准确地告诉您哪两个文件/行发生了竞争。从阅读开始。如果您需要帮助,请在问题中包含该输出。此代码段创建1000个执行redis SET命令的goroutine,因此您可以看到数据争用在此处发生err:=Setkey,strconv.Itoai。争用是因为for循环正在更新i,而您的goroutine正在同时读取i。如何转储i。。。我以为我用的redigo不正确,谢谢你!如果你仔细观察种族检测器的输出,它会告诉你正确的方向:阅读。。。redis_测试。go:48和上一次写入时间。。。redis_test.go:45这将其范围缩小到写在第45行、读在第48行的变量。符合该描述的唯一变量是 我