第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

在 Golang 中測(cè)試一次條件

在 Golang 中測(cè)試一次條件

Go
浮云間 2022-05-23 18:02:23
我有一個(gè)模塊,它依賴(lài)于通過(guò)調(diào)用外部服務(wù)來(lái)填充緩存,如下所示:func (provider *Cache) GetItem(productId string, skuId string, itemType string) (*Item, error) {    // First, create the key we'll use to uniquely identify the item    key := fmt.Sprintf("%s:%s", productId, skuId)    // Now, attempt to get the concurrency control associated with the item key    // If we couldn't find it then create one and add it to the map    var once *sync.Once    if entry, ok := provider.lockMap.Load(key); ok {        once = entry.(*sync.Once)    } else {        once = &sync.Once{}        provider.lockMap.Store(key, once)    }    // Now, use the concurrency control to attempt to request the item    // but only once. Channel any errors that occur    cErr := make(chan error, 1)    once.Do(func() {        // We didn't find the item in the cache so we'll have to get it from the partner-center        item, err := provider.client.GetItem(productId, skuId)        if err != nil {            cErr <- err            return        }        // Add the item to the cache        provider.cache.Store(key, &item)    })    // Attempt to read an error from the channel; if we get one then return it    // Otherwise, pull the item out of the cache. We have to use the select here because this is    // the only way to attempt to read from a channel without it blocking    var sku interface{}    select {    case err, ok := <-cErr:        if ok {            return nil, err        }    default:        item, _ = provider.cache.Load(key)    }    // Now, pull out a reference to the item and return it    return item.(*Item), nil}這種方法按我的預(yù)期工作。我的問(wèn)題是測(cè)試;專(zhuān)門(mén)測(cè)試以確保該GetItem方法僅針對(duì)給定的鍵值調(diào)用一次。我的測(cè)試代碼如下:var _ = Describe("Item Tests", func() {    It("GetItem - Not cached, two concurrent requests - Client called once", func() {        // setup cache    })})我遇到的問(wèn)題是,有時(shí)這個(gè)測(cè)試會(huì)失敗,因?yàn)檎?qǐng)求計(jì)數(shù)是 2,而在注釋行中預(yù)期它是 1。此故障不一致,我不太確定如何調(diào)試此問(wèn)題。任何幫助將不勝感激。
查看完整描述

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ì)更容易。


查看完整回答
反對(duì) 回復(fù) 2022-05-23
  • 1 回答
  • 0 關(guān)注
  • 165 瀏覽
慕課專(zhuān)欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢(xún)優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)