亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Go 中對單個計算資源的多個請求

Go 中對單個計算資源的多個請求

Go
翻翻過去那場雪 2023-08-14 14:53:53
尋找更 Go 式的解決方案來解決以下問題:假設服務器有多個并行傳入請求,要求使用 key 的資源key。由于計算此資源非常昂貴/耗時,因此我們希望確保僅計算一次。有無限多個可能的鍵。一種簡單的實現:if hasCachedValue(key) {   return cachedValue(key)}if somebodyElseWorkingOn(key) {   waitUntilReady(key)} else {   buildCacheValue(key) // time consuming}return cachedValue(key)到目前為止,我們已經使用共享解決了這個問題map[string]chan bool,其中第一個請求插入了 chan for key,而后續請求在值準備好時等待該 chan 的關閉。為了保護地圖,我們使用了sync.Mutex,但我們感覺有一個更好、更 Go 式的解決方案。
查看完整描述

3 回答

?
波斯汪

TA貢獻1811條經驗 獲得超4個贊

使用單程套餐。為該組聲明一個包級變量:

var?g?singleflight.Group

使用以下代碼獲取值:

v, err, _ := g.Do(key, func() (interface{}, error) {

? ? if !hasCachedValue(key) {

? ? ? ? buildCacheValue(key)

? ? }

? ? return cachedValue(key), nil

})

if err != nil {

? ? // handle error

}

x := v.(valueType) // assert to type returned by cachedValue

// do something with x


查看完整回答
反對 回復 2023-08-14
?
肥皂起泡泡

TA貢獻1829條經驗 獲得超6個贊

這是一個簡單的代碼,可以完成您想要的操作。我測試了它,它工作沒有問題。Go 競爭條件檢查器沒有檢測到任何問題。


type Cache struct {

    mtx sync.RWMutex

    m map[KeyType]*CacheValue

}


type CacheValue struct {

    val *ValueType

    mtx sync.Mutex

}


func NewCache() *Cache {

    return &Cache{m: make(map[KeyType]*CacheValue)}

}


func (c *Cache) Get(key KeyType) *ValueType {

    c.mtx.RLock()

    v := c.m[key]

    c.mtx.RUnlock()

    if v != nil {

        v.mtx.Lock()

        x := v.val

        v.mtx.Unlock()

        if x != nil {

            return x

        }

    }


    if v == nil {

        c.mtx.Lock()

        v = c.m[key]

        if v == nil {

            v = &CacheValue{}

            c.m[key] = v

        }

        c.mtx.Unlock()

    }


    v.mtx.Lock()

    if v.val == nil {

        v.val = buildValue(key)

    }

    v.mtx.Unlock()

    return v.val

}


查看完整回答
反對 回復 2023-08-14
?
梵蒂岡之花

TA貢獻1900條經驗 獲得超5個贊

受到經常用于描述通道的乒乓球示例的啟發,我們嘗試了僅通道方法。球保存有關正在生成的密鑰的狀態,并且球在共享通道的請求之間傳遞:


import "time"


var table = make(chan map[string]chan bool)


func keeper() {

    for {

        ball := <- table

        table <- ball

    }

}


func getResource(key string) {

    // Take ball from table

    ball := <- table


    if wait, ok := ball[key]; ok{

        println("Somebody else working on " + key + ", waiting")

        table <- ball

        <- wait

    } else {

        println("I will build " + key)

        ball[key] = make(chan bool)


        // Throw away ball

        table <- ball


        // Building value

        time.Sleep(time.Millisecond * 10)

        println("I built value for " + key + "!")


        // Clean up ball

        ball = <- table

        close(ball[key])

        delete(ball, key)

        table <- ball

    }


    println("Now value for " + key + " has been built")

}


func main(){

    go keeper()


    ball := make(map[string]chan bool)

    table <- ball


    key := "key"

    go getResource(key)

    go getResource(key)

    go getResource(key)


    time.Sleep(time.Second)

}


查看完整回答
反對 回復 2023-08-14
  • 3 回答
  • 0 關注
  • 193 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號