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

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

Golang 檢測正在進行的請求

Golang 檢測正在進行的請求

Go
斯蒂芬大帝 2021-10-18 14:54:06
我想知道是否已經有一個圖書館可以做到這一點,或者是否有解決以下問題的建議:客戶端 A 請求資源 A,這是一個長時間運行的請求,因為資源 A 很昂貴并且會導致緩存未命中。與此同時,客戶端 B 請求資源 A,現在它仍然是緩存未命中,因為客戶端 A 的請求尚未返回并填充緩存。因此,當客戶端 A 的請求完成并填充緩存時,客戶端 B 應該阻塞并收到通知,而不是發出新的請求來生成資源 A。我認為組緩存庫有一些類似的東西,但我無法瀏覽代碼來弄清楚它們是如何做到的,我也不想將實現與它聯系起來并將其用作依賴項。到目前為止,我唯一的解決方案是 pub-sub 類型的東西,其中我們有當前正在進行的請求的全局映射,以 reqID 作為鍵。當 req1 到來時,它在映射中設置它的 ID,req2 到來并檢查它的 id 是否在映射中,因為它請求的是與它相同的資源,所以我們阻塞了一個通知通道。當 req1 完成時,它會做 3 件事:從地圖中驅逐它的 ID將條目保存在緩存中向通知器通道發送一個帶有其 ID 的廣播 req2 接收通知,解除阻塞并從緩存中獲取。由于 go 沒有內置對廣播的支持,因此可能有 1 個灌漿監聽廣播頻道,然后為每個請求保留要廣播的訂閱者列表,或者我們可能將映射更改為 reqId => list(broadcastChannelSubscribers)。沿著這些路線的東西。如果您認為使用 Go 的原語有更好的方法,任何輸入都將不勝感激。這個解決方案中唯一困擾我的是這張全局地圖,被鎖包圍,我認為它很快就會成為一個瓶頸。如果您有一些非鎖定的想法,即使它們是概率性的,我也很高興聽到它們。
查看完整描述

3 回答

?
慕哥6287543

TA貢獻1831條經驗 獲得超10個贊

這讓我想起了一個問題,有人在實施類似的事情:

合并頻道中的項目

我給出了一個實現這樣一個中間層的例子的答案。我認為這符合您的想法:定期跟蹤對同一資源的請求并防止它們并行重新計算。

如果您有一個單獨的例程負責接收請求和管理對緩存的訪問,則不需要顯式鎖(盡管有一個隱藏在通道中)。無論如何,我不知道你的應用程序的細節,但考慮到你需要檢查緩存(可能被鎖定)和(偶爾)執行丟失條目的昂貴計算——鎖定地圖查找對我來說似乎不是一個大問題。如果您認為這會有所幫助,您也可以始終跨越更多這樣的中間層例程,但是您需要一種確定性方式來路由請求(因此每個緩存條目都由單個例程管理)。

很抱歉沒有給您帶來靈丹妙藥的解決方案,但聽起來您無論如何都可以很好地解決問題。



查看完整回答
反對 回復 2021-10-18
?
慕桂英4014372

TA貢獻1871條經驗 獲得超13個贊

緩存和性能問題總是很棘手,你應該總是制定一個基本的解決方案來進行基準測試,以確保你的假設是正確的。但是如果我們知道瓶頸是獲取資源并且緩存會帶來顯著的回報,那么你可以使用 Go 的通道來實現排隊。假設這response是您的資源類型。


type request struct {

     back chan *response

}


func main() {

    c := make(chan request,10) // non-blocking

    go func(input chan request){

        var cached *response

        for _,i := range input {

            if cached == nil { // only make request once

                cached = makeLongRunningRequest()

            }

            i.back <- cached

        }

    }(c)


    resp := make(chan *response)


    c <- request{resp} // cache miss

    c <- request{resp} // will get queued

    c <- request{resp} // will get queued


    for _,r := range resp {

        // do something with response

    }

}

這里我們只獲取一個資源,但你可以為你想要獲取的每個資源啟動一個 goroutine。Goroutines 很便宜,所以除非你需要同時緩存數百萬個資源,否則你應該沒問題。你當然也可以在一段時間后殺死你的 goroutine。


為了跟蹤哪個資源 id 屬于哪個頻道,我會使用地圖


map[resourceId]chan request

帶有互斥鎖。同樣,如果獲取資源是瓶頸,那么鎖定地圖的成本應該可以忽略不計。如果鎖定地圖被證明是一個問題,請考慮使用分片地圖。


總的來說,您似乎進展順利。我建議盡量讓你的設計盡可能簡單,并在可能的情況下使用通道而不是鎖。它們確實可以防止可怕的并發錯誤。


查看完整回答
反對 回復 2021-10-18
  • 3 回答
  • 0 關注
  • 288 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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