1 回答

TA貢獻(xiàn)1810條經(jīng)驗(yàn) 獲得超4個(gè)贊
我認(rèn)為您的測(cè)試有時(shí)會(huì)失敗,因?yàn)槟木彺鏌o(wú)法保證它只獲取一次項(xiàng)目,而且您很幸運(yùn)測(cè)試抓住了這一點(diǎn)。
如果一個(gè) item 不在其中,并且 2 個(gè)并發(fā) goroutines 同時(shí)調(diào)用Cache.GetItem(),可能lockMap.Load()會(huì)在兩者中報(bào)告 key 不在 map 中,兩個(gè) goroutines 都創(chuàng)建一個(gè)sync.Once,并且都將自己的實(shí)例存儲(chǔ)在 map 中(顯然只有一個(gè)——后者——將保留在地圖中,但您的緩存不會(huì)檢查這一點(diǎn))。
然后 2 個(gè) goroutine 都會(huì)調(diào)用client.GetItem(),因?yàn)?2 個(gè)單獨(dú)sync.Once的不提供同步。只有使用相同的sync.Once實(shí)例,才能保證傳遞給的函數(shù)Once.Do()只執(zhí)行一次。
我認(rèn)為sync.Mutex避免sync.Once在這里創(chuàng)建和使用 2 會(huì)更容易、更合適。
或者由于您已經(jīng)在使用sync.Map,您可以使用以下Map.LoadOrStore()方法:創(chuàng)建一個(gè)sync.Once,并將其傳遞給Map.LoadOrStore(). 如果鍵已經(jīng)在地圖中,請(qǐng)使用返回的sync.Once. 如果密鑰不在地圖中,您sync.Once將存儲(chǔ)在其中,因此您可以使用它。這將確保沒(méi)有多個(gè)并發(fā) goroutine 可以sync.once在其中存儲(chǔ)多個(gè)實(shí)例。
像這樣的東西:
var once *sync.Once
if entry, loaded := provider.lockMap.LoadOrStore(key, once); loaded {
// Was already in the map, use the loaded Once
once = entry.(*sync.Once)
}
這個(gè)解決方案仍然不完美:如果 2 個(gè) goroutineCache.GetItem()同時(shí)調(diào)用,只有一個(gè)會(huì)嘗試從客戶(hù)端獲取項(xiàng)目,但如果失敗,只有這個(gè) goroutine 會(huì)報(bào)告錯(cuò)誤,另一個(gè) goroutine 不會(huì)嘗試獲取來(lái)自客戶(hù)端的項(xiàng)目,但將從地圖加載它并且您不檢查加載是否成功。你應(yīng)該,如果它不在地圖中,這意味著另一個(gè)并發(fā)嘗試未能獲得它。所以你應(yīng)該報(bào)告錯(cuò)誤(并清除sync.Once)。
如您所見(jiàn),它變得越來(lái)越復(fù)雜。我堅(jiān)持我之前的建議:sync.Mutex在這里使用 a 會(huì)更容易。
- 1 回答
- 0 關(guān)注
- 165 瀏覽
添加回答
舉報(bào)