不少時候性能問題老是發生在一些不起眼的地方。最近作一個性能問題分析的時候發現,一個函數裏面使用因爲字符串拼接產生的臨時字符串致使內存上漲了40%(120G 內存的機器),而這些臨時字符串給 GC 也帶來了很是大的負擔,成爲主要的性能瓶頸,而這些字符串做爲 map 的 key,又必需要拼接,因此想到了直接使用 hash 後的值做爲 map 的 key,而這個 hash 值使用累加 hash 計算得出。git
所謂累加 hash,就是對字符串的 hash 能夠分爲任意多段,對每一段連續 hash,結果累加,對於任意一種分段方式,最後能獲得一致的 hash 結果,好比:H.hash("hello world")
, H.hash("hello").hash(" ").hash("world")
, H.hash("hello wo").hash("rld)"
這些結果最後都應該是一致的,利用這個特性,就能作到對多個字符串哈希而不用拼接github
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) }
使用上也很簡單golang
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/函數