golang 效能優化之累加雜湊

hatlonely發表於2018-04-12

很多時候效能問題總是發生在一些不起眼的地方。最近做一個效能問題分析的時候發現,一個函式裡面使用由於字串拼接產生的臨時字串導致記憶體上漲了40%(120G 記憶體的機器),而這些臨時字串給 GC 也帶來了非常大的負擔,成為主要的效能瓶頸,而這些字串作為 map 的 key,又必須要拼接,所以想到了直接使用 hash 後的值作為 map 的 key,而這個 hash 值使用累加 hash 計算得出。

所謂累加 hash,就是對字串的 hash 可以分為任意多段,對每一段連續 hash,結果累加,對於任意一種分段方式,最後能得到一致的 hash 結果,比如:H.hash("hello world"), H.hash("hello").hash(" ").hash("world"), H.hash("hello wo").hash("rld)" 這些結果最後都應該是一致的,利用這個特性,就能做到對多個字串雜湊而不用拼接

BKDR hash 實現

type StringHasherBKDR uint64

// NewStringHasherBKDR 建立一個新的 Hasher
func NewStringHasherBKDR() StringHasherBKDR {
    return StringHasherBKDR(0)
}

// AddStr 增加一個字串
func (bkdr StringHasherBKDR) AddStr(str string) StringHasherBKDR {
    val := uint64(bkdr)
    for i := 0; i < len(str); i++ {
        val = val*131 + uint64(str[i])
    }
    return StringHasherBKDR(val)
}

// AddInt 新增一個 int 值
func (bkdr StringHasherBKDR) AddInt(i uint64) StringHasherBKDR {
    val := uint64(bkdr)
    val = val*131 + i
    return StringHasherBKDR(val)
}

// Val 轉成 uint64 的值
func (bkdr StringHasherBKDR) Val() uint64 {
    return uint64(bkdr)
}

使用上也很簡單

hasher := NewStringHasherBKDR()
So(hasher.AddStr("hello world").Val(), ShouldEqual, hasher.AddStr("hello").AddStr(" ").AddStr("world").Val())

參考連結

轉載請註明出處 本文連結:http://www.hatlonely.com/2018/04/12/golang-%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8B%E7%B4%AF%E5%8A%A0%E5%93%88%E5%B8%8C/

相關文章