最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

go內(nèi)存緩存BigCache實現(xiàn)BytesQueue源碼解讀

 更新時間:2023年09月05日 15:35:12   作者:海生  
這篇文章主要為大家介紹了go內(nèi)存緩存BigCache實現(xiàn)BytesQueue源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

一、BytesQueue結(jié)構(gòu)

BytesQueue結(jié)構(gòu),是bigcache真正數(shù)據(jù)存儲的地方。

值得注意的是刪除緩存元素的時候bigcache只是在map[uint64]uint32中刪除了它的索引,byte數(shù)組里的空間是不會釋放的。

在 bigCache 中,所有的 value 都是存在一個 BytesQueue 中的,從實現(xiàn)可知,所有的用戶存儲數(shù)據(jù)經(jīng)由序列化后存入 array []byte

// BytesQueue is a non-thread safe queue type of fifo based on bytes array.
// BytesQueue 是基于字節(jié)數(shù)組的非線程安全隊列類型的FIFO。
// For every push operation index of entry is returned. It can be used to read the entry later
// 對于每個推送操作索引,都會返回。它可用于稍后閱讀條目。
type BytesQueue struct {
    full         bool
    array        []byte // 真正存儲數(shù)據(jù)的地方
    capacity     int    // array 的容量
    maxCapacity  int    // array 可申請的最大容量
    head         int
    tail         int // 下次可以插入 item 的位置
    count        int // 當前插入的 item 數(shù)量
    rightMargin  int
    headerBuffer []byte // 插入前做臨時 buffer 所用(slice-copy)
    verbose      bool   // 打印 log 開關(guān)
}

初始化BytesQueue方法

func NewBytesQueue(capacity int, maxCapacity int, verbose bool) *BytesQueue {
    return &BytesQueue{
        array:        make([]byte, capacity), // 真正存儲數(shù)據(jù)的地方,長度為capacity,直接初始化每個值
        capacity:     capacity,
        maxCapacity:  maxCapacity,
        headerBuffer: make([]byte, binary.MaxVarintLen32),
        tail:         leftMarginIndex,
        head:         leftMarginIndex,
        rightMargin:  leftMarginIndex,
        verbose:      verbose,
    }
}

我們通過維護下面幾個變量來實現(xiàn)存儲位移及標識:

head:起始位置(也可以理解為,當前最老的數(shù)據(jù)的位置,刪除的邏輯從這個位置開始)

tail:下次可以插入 item 的位置

capacity:標識 array 的容量

count:當前已經(jīng)插入的 item 的數(shù)量

maxCapacity:標識 array 可以申請的最大容量

rightMargin:用于標識隊列中最后一個元素的位置,是一個絕對位置。

leftMarginIndex:常量,值為 1,標識隊列的開頭位置(0 號不用)

注意, head 和 tail 以及 rightMargin 的初始值都是 leftMarginIndex。BytesQueue 使用 []byte 類型來模擬隊列,插入數(shù)據(jù)從 tail 位置,刪除數(shù)據(jù)從 head 位置。為標準的FIFO隊列。

二、如何使用這個BytesQueue

1、插入item到隊列,通過調(diào)用BytesQueue.Push([]byte) 方法,我們可以把[]byte類型的數(shù)據(jù)插入到BytesQueue中。

返回為這個值存儲的index索引。

func TestQueuePush(t *testing.T) {
    // 初始化一個byte隊列
    queue := NewBytesQueue(5, 0, false)
    t.Log(queue) // &{false [0 0 0 0 0] 5 0 1 1 0 1 [0 0 0 0 0] false}
    // 調(diào)用Push方法,會返回獲取這個值的index索引
    index, err := queue.Push([]byte("a"))
    t.Log(index, err) // 1 <nil>
    index, err = queue.Push([]byte("b"))
    t.Log(index, err) // 3 <nil>
    // 通過index索引就可以獲取到這個值
    a, err2 := queue.Get(1)
    t.Log(string(a), err2) // a <nil>
    b, err2 := queue.Get(3)
    t.Log(string(b), err2) // b <nil>
}

這樣,我們就相當于一個值,和一個索引index對應(yīng)了。

通過一個索引可以快速的獲取到這個值。

bigcache我們通過BytesQueue,存儲數(shù)據(jù)。

再用一個map,記錄一下這個index和值的 對應(yīng)關(guān)系。

就可O(1)的時間復(fù)雜度,查詢BytesQueue的所有數(shù)據(jù)。

-----注意:為什么通過index可以獲取value的值?

因為我們再push的 []byte的時候,最終存儲這個[]byte會用一個8字節(jié)存儲這個entry的長度。

這樣通過index我們獲取到這個長度,然后就可以獲取到這個數(shù)據(jù)。

func (q *BytesQueue) Push(data []byte) (int, error) {
    neededSize := getNeededSize(len(data))
    ....... // 省略
    index := q.tail

    q.push(data, neededSize)

    return index, nil
}

從Push()方法中,我們看到調(diào)用了一個push()方法。我們打開源代碼,可以看到最終在保存數(shù)據(jù)的時候,先用一個8字節(jié)保存了 data的長度。

func (q *BytesQueue) push(data []byte, len int) {
    headerEntrySize := binary.PutUvarint(q.headerBuffer, uint64(len))
    q.copy(q.headerBuffer, headerEntrySize) // 用一個8字節(jié)保存data的長度
    q.copy(data, len-headerEntrySize)       // 寫入data
    if q.tail > q.head {
        q.rightMargin = q.tail
    }
    if q.tail == q.head {
        q.full = true
    }
    q.count++
}

byteQueue中每個元素都有2部分組成,前8個byte是數(shù)據(jù)的長度,后面是數(shù)據(jù)的值本身,每個byteQueue中每個元素的最大長度是8個字節(jié),2的64次方。

以上就是go內(nèi)存緩存BigCache實現(xiàn)BytesQueue源碼解讀的詳細內(nèi)容,更多關(guān)于go內(nèi)存緩存BigCache BytesQueue的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go使用context控制協(xié)程取消的實戰(zhàn)案例

    Go使用context控制協(xié)程取消的實戰(zhàn)案例

    在并發(fā)編程中,合理地控制協(xié)程的生命周期是保證程序穩(wěn)定性和資源可控使用的關(guān)鍵,Go語言標準庫中的context包正是為了解決這一問題而生,它為我們提供了取消信號、超時控制、請求作用域的值傳遞等功能,本文將通過一個實際案例,演示如何使用context控制協(xié)程的取消
    2025-08-08
  • GO語言操作Elasticsearch示例分享

    GO語言操作Elasticsearch示例分享

    這篇文章主要介紹了GO語言操作Elasticsearch示例分享的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • golang結(jié)構(gòu)體slice排序方式

    golang結(jié)構(gòu)體slice排序方式

    go語言的slice()不僅可以對int類型的數(shù)組進行排序,還可以對struct類型的數(shù)組進行排序,排序函數(shù)包括Slice()、SliceStable()和SliceIsSorted(),結(jié)構(gòu)體可以定義為更復(fù)雜的類型
    2025-12-12
  • Go語言中棧擴容和??s容的使用

    Go語言中棧擴容和??s容的使用

    Go 語言中的棧擴容和??s容是運行時動態(tài)管理 goroutine 棧內(nèi)存的機制,這是 Go 高并發(fā)性能的關(guān)鍵特性之一,本文就來詳細的介紹一下棧擴容和??s容的使用,感興趣的可以了解一下
    2025-10-10
  • Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究

    Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究

    這篇文章主要為大家介紹了Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • Golang接口的定義與空接口及斷言的使用示例

    Golang接口的定義與空接口及斷言的使用示例

    在?Golang?中,接口是一種類型,它是由一組方法簽名組成的抽象集合。這篇文章主要為大家介紹了Golang接口的具體使用,希望對大家有所幫助,空接口是特殊形式的接口類型,普通的接口都有方法,而空接口沒有定義任何方法口,也因此,我們可以說所有類型都至少實現(xiàn)了空接口
    2023-04-04
  • go語言算法題解二叉樹的拷貝、鏡像和對稱

    go語言算法題解二叉樹的拷貝、鏡像和對稱

    這篇文章主要為大家詳細介紹了go語言算法題解二叉樹的拷貝、鏡像和對稱,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-01-01
  • golang進程啟動及監(jiān)控方式

    golang進程啟動及監(jiān)控方式

    本文介紹了使用Golang實現(xiàn)進程守護和進程監(jiān)控的方法,提供了兩種具體實現(xiàn)方式:一種是代碼集成到業(yè)務(wù)代碼中,通過命令行參數(shù)判斷是否啟動守護進程;另一種是單獨編寫守護進程程序,不與業(yè)務(wù)代碼耦合,可作為通用的守護進程程序,兩種方式各有優(yōu)缺點,適用于不同的場景
    2026-04-04
  • Go如何在HTTP請求中操作cookie教程詳解

    Go如何在HTTP請求中操作cookie教程詳解

    這篇文章主要為大家介紹了Go如何在HTTP請求中操作cookie教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • 學(xué)會提升Go語言編碼效率技巧拒絕加班!

    學(xué)會提升Go語言編碼效率技巧拒絕加班!

    這篇文章主要為大家介紹了Go語言編碼效率提升技巧詳解,學(xué)會了從此拒絕加班,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12

最新評論

靖安县| 鞍山市| 古蔺县| 吉水县| 梁平县| 根河市| 洪泽县| 河池市| 红河县| 马山县| 武陟县| 光山县| 缙云县| 石台县| 沐川县| 西和县| 屯门区| 赤城县| 井陉县| 南岸区| 阿巴嘎旗| 平和县| 卓资县| 望谟县| 文水县| 黑河市| 股票| 八宿县| 宿松县| 田阳县| 手游| 女性| 报价| 扎赉特旗| 鹿泉市| 海淀区| 云林县| 伊金霍洛旗| 江阴市| 龙岩市| 沂源县|