golang使用map支持高并發(fā)的方法(1000萬次操作14ms)
語言原生的map存在2個問題:
1)不是線程安全的;
2)數(shù)據(jù)量大時候需要盡量避免使用string等,GC壓力很大;
有人使用泛型實現(xiàn)了相關(guān)的cocurent-map,(https://github.com/orcaman/concurrent-map)但是關(guān)于鍵值部分仍然默認使用了string,為了提高效率,這里對其做了一些修改,讓鍵值也可以自定義類型:https://github.com/robinfoxnan/go_concurrent_map
基本使用方法:
// Create a new map. m := cache.NewConcurrentMap[uint64, string]() // Sets item within map, sets "bar" under key "foo" m.Set(199010212, "bar") // Retrieve item from map. bar, ok := m.Get(199010212) fmt.Println(bar, ok) // Removes item under key "foo" m.Remove(199010212)
為了實現(xiàn)計數(shù)器等,需要在加鎖期間更新,需要使用回調(diào)函數(shù):
// 計數(shù)器 type BaseCounter struct { Count uint64 CountLast uint64 } var MapOfAppUserCount ConcurrentMap[uint64, *AppUserCounter] func InitMaps() { MapOfAppVistedCount = NewConcurrentMap[uint64, *BaseCounter]() } // 沒有值,則設(shè)置;如果有,則更新; 新增的部分通過新的值傳遞過來! func appAddCallBack(exist bool, valueInMap *BaseCounter, newValue *BaseCounter) *BaseCounter { if exist == false { return newValue } else { valueInMap.Count += newValue.Count return valueInMap } } // 對應(yīng)用計數(shù)器加i func AppAddBy(key uint64, i uint64) uint64 { c := BaseCounter{i, i} res := MapOfAppVistedCount.Upsert(key, &c, appAddCallBack) if res != nil { return res.Count } return 0 }
計數(shù)器的使用如下:
cache.InitMaps() cache.AppAddBy(i, 1)
性能:
1)單線程初始化1~1000w的計數(shù)器,2412 ms
2)分給100個協(xié)程,14ms
測試代碼如下:
func testSingle() { cache.InitMaps() timeUnixNano1 := time.Now().UnixMilli() // 100萬次更新 for i := uint64(0); i < 10000000; i++ { cache.AppAddBy(i, 1) } timeUnixNano2 := time.Now().UnixMilli() delta := timeUnixNano2 - timeUnixNano1 fmt.Println("cost: ", delta, " ms") count := cache.AppAddBy(1, 1) fmt.Println(count) count = cache.AppAddBy(1, 2) fmt.Println(count) count = cache.AppAddBy(1, 3) fmt.Println(count) } var N int = 10000000 func doInsert(n int, index int, g *sync.WaitGroup) { m := N / n start := index * m //fmt.Println("thread ", index, "from ", start) for i := uint64(start); i < uint64(m); i++ { cache.AppAddBy(i, 1) } if g != nil { g.Done() } } func testMulti() { cache.InitMaps() group := sync.WaitGroup{} n := 100 group.Add(n) timeUnixNano1 := time.Now().UnixMilli() for i := 0; i < n; i++ { go doInsert(n, i, &group) } group.Wait() timeUnixNano2 := time.Now().UnixMilli() delta := timeUnixNano2 - timeUnixNano1 fmt.Println("cost: ", delta, " ms") }
到此這篇關(guān)于golang讓map支持高并發(fā)(1000萬次操作14ms)的文章就介紹到這了,更多相關(guān)golang map并發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang實現(xiàn)簡單工廠、方法工廠、抽象工廠三種設(shè)計模式
這篇文章介紹了golang實現(xiàn)簡單工廠、方法工廠、抽象工廠三種設(shè)計模式的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04idea搭建go環(huán)境實現(xiàn)go語言開發(fā)
這篇文章主要給大家介紹了關(guān)于idea搭建go環(huán)境實現(xiàn)go語言開發(fā)的相關(guān)資料,文中通過圖文介紹以及代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用go具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01