2015-12-02 2 views
2

У меня есть цикл, и я получаю эту ошибку, я бегу go run -race main.goКаким образом этот цикл считается гонки данных [Golang]

Это петля в вопросе:

var wg sync.WaitGroup 

for _, member := range p.Members { << Line 254 
    go func() { 
     wg.Add(1) 
     _, err := db.Exec("UPDATE party_members SET active = ? WHERE steamid = ?", false, member.SteamID) << Line 257 
     if err != nil { 
      log.Println(err) 
     } 
     _, err = db.Exec("INSERT INTO party_members SET belongs_to =?, active = ?, steamid = ?", partyUUID, true, member.SteamID) 
     if err != nil { 
      log.Println(err) 
     } 
     wg.Done() 
    }() << Line 266 
} 

, а затем это ошибка, я получаю:

WARNING: DATA RACE 
Read by goroutine 44: 
    BLAH/controllers/partybot.func·001() 
     /Users/Dev/gocode/src/BLAH/controllers/partybot/partybot.go:257 +0x136 

Previous write by goroutine 43: 
    BLAH/controllers/partybot.(*PartialParty).SendReadyCheck() 
     /Users/Dev/gocode/src/BLAH/controllers/partybot/partybot.go:254 +0xda5 

Goroutine 44 (running) created at: 
    BLAH/controllers/partybot.(*PartialParty).SendReadyCheck() 
     /Users/Dev/gocode/src/BLAH/controllers/partybot/partybot.go:266 +0xf13 

Goroutine 43 (finished) created at: 
    BLAH/controllers/partybot.(*PartyHub).SortMemberIntoParty() 
     /Users/Dev/gocode/src/BLAH/controllers/partybot/partybot.go:173 +0xdb9 
    BLAH/controllers/partybot.(*Connection).readPump() 
     /Users/Dev/gocode/src/BLAH/controllers/partybot/partybot.go:359 +0x1872 
    BLAH/controllers/partybot.WSPartyBot() 
     /Users/Dev/gocode/src/BLAH/controllers/partybot/partybot.go:440 +0x4f0 
    net/http.HandlerFunc.ServeHTTP() 
     /usr/local/go/src/net/http/server.go:1265 +0x4e 
    github.com/gorilla/mux.(*Router).ServeHTTP() 
     /Users/Dev/gocode/src/github.com/gorilla/mux/mux.go:98 +0x377 
    BLAH/controllers/common.func·001() 
     /Users/Dev/gocode/src/BLAH/controllers/common/common.go:36 +0xc2 
    net/http.HandlerFunc.ServeHTTP() 
     /usr/local/go/src/net/http/server.go:1265 +0x4e 
    net/http.(*ServeMux).ServeHTTP() 
     /usr/local/go/src/net/http/server.go:1541 +0x20c 
    net/http.serverHandler.ServeHTTP() 
     /usr/local/go/src/net/http/server.go:1703 +0x1f6 
    net/http.(*conn).serve() 
     /usr/local/go/src/net/http/server.go:1204 +0x1087 
================== 

Я не знаю, почему это гонка данных, как я довольно новый Пойти в любом случае, если кто-нибудь может сказать мне, почему это было бы здорово, я ознаменовало линии, о которых идет речь.

ответ

5

проблема заключается в том, что goroutine обращается к переменной «член» через закрытие, и в результате эта ссылка оценивается, когда ее достигнуто (т.е. она видит значение члена на момент выполнения goroutine, а не когда оно было созданный с помощью функции go func() ..., переменная-член обновляется по циклу, поэтому между обновлениями цикла и гортанами, которые вы начали читать, существует гонка (вы обнаружите, ваш db не видит точного набора членов из коллекции). Обычно вы разрешаете это, заставляя оценивать переменную в цикле, создавая локальный var или добавляя его в качестве параметра функции func, например

var wg sync.WaitGroup 

for _, member := range p.Members { 
    wg.Add(1) 
    m := member 
    go func() { 
     _, err := db.Exec("UPDATE party_members SET active = ? WHERE steamid = ?", false, m.SteamID) 
     ... 
     wg.Done() 
    }() 
} 

или

var wg sync.WaitGroup 

for _, member := range p.Members { 
    wg.Add(1) 
    go func(m memberType) { 
     _, err := db.Exec("UPDATE party_members SET active = ? WHERE steamid = ?", false, m.SteamID) 
     ... 
     wg.Done() 
    }(member) 
} 

также отмечают, что вам нужно вызвать wg.Add (1) из контура, а не из самого goroutine.

+0

есть аналогичный пример и объяснение здесь http://www.goinggo.net/2014/06/pitfalls-with-closures-in-go.html – superfell

+0

это как искусство, спасибо! бил мою голову со стены в течение последних нескольких часов – Datsik

+0

Быстрый вопрос, после фиксации этой гонке данных У меня есть еще 2 гонка данных Мне нужно вылечить, какие-нибудь советы по отладке данных? Кажется, что у обоих есть доступ к одной и той же «карте» и установке в нее переменной, я попытался поместить мьютекс вокруг карты, но у нее все еще есть гонка – Datsik