我正在針對我的 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 關注
- 118 瀏覽
添加回答
舉報
0/150
提交
取消