日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

go 分段锁ConcurrentMap,map+读写锁,sync.map的效率测试

發布時間:2024/2/28 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 go 分段锁ConcurrentMap,map+读写锁,sync.map的效率测试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

分段鎖ConcurrentMap的實現請參考筆者的另外一篇博客:

go 分段鎖ConcurrentMap的實現源碼

效率測試結論:

1. go自帶的map不是多協程安全的

2. 分段鎖ConcurrentMap是多協程安全的,且效率最高;sync.map效率次之,傳統的map+讀寫鎖效率最低

3.?ConcurrentMap中鎖的個數越多,效率越高,因為爭奪同一把鎖的概率降低了

測試流程:

1. 產生1萬個key-value對,加入到各個測試map中

2. 開始計時

3. 開啟兩個協程,一個寫協程隨機賦值10萬次,一個讀協程隨機訪問10萬次

4. 結束計時,打印出耗時,內存操作等信息

測試結果如下圖(紅框處是每次測試的耗時):

源碼如下:

測試的源碼main_test.go

package mainimport ("math/rand""strconv""sync""testing" )// 10萬次的賦值,10萬次的讀取 var times int = 100000// 測試ConcurrentMap func BenchmarkTestConcurrentMap(b *testing.B) {for k := 0; k < b.N; k++ {b.StopTimer()// 產生10000個不重復的鍵值對(string -> int)testKV := map[string]int{}for i := 0; i < 10000; i++ {testKV[strconv.Itoa(i)] = i}// 新建一個ConcurrentMappMap := NewConcurrentMap()// set到map中for k, v := range testKV {pMap.Set(k, v)}// 開始計時b.StartTimer()wg := sync.WaitGroup{}wg.Add(2)// 賦值go func() {// 對隨機key,賦值times次for i := 0; i < times; i++ {index := rand.Intn(times)pMap.Set(strconv.Itoa(index), index+1)}wg.Done()}()// 讀取go func() {// 對隨機key,讀取times次for i := 0; i < times; i++ {index := rand.Intn(times)pMap.Get(strconv.Itoa(index))}wg.Done()}()// 等待兩個協程處理完畢wg.Wait()} }// 測試map加鎖 func BenchmarkTestMap(b *testing.B) {for k := 0; k < b.N; k++ {b.StopTimer()// 產生10000個不重復的鍵值對(string -> int)testKV := map[string]int{}for i := 0; i < 10000; i++ {testKV[strconv.Itoa(i)] = i}// 新建一個MutexMappMap := NewMutexMap()// set到map中for k, v := range testKV {pMap.Set(k, v)}// 開始計時b.StartTimer()wg := sync.WaitGroup{}wg.Add(2)// 賦值go func() {// 對隨機key,賦值100萬次for i := 0; i < times; i++ {index := rand.Intn(times)pMap.Set(strconv.Itoa(index), index+1)}wg.Done()}()// 讀取go func() {// 對隨機key,讀取100萬次for i := 0; i < times; i++ {index := rand.Intn(times)pMap.Get(strconv.Itoa(index))}wg.Done()}()// 等待兩個協程處理完畢wg.Wait()} }// 測試sync.map func BenchmarkTestSyncMap(b *testing.B) {for k := 0; k < b.N; k++ {b.StopTimer()// 產生10000個不重復的鍵值對(string -> int)testKV := map[string]int{}for i := 0; i < 10000; i++ {testKV[strconv.Itoa(i)] = i}// 新建一個sync.MappMap := &sync.Map{}// set到map中for k, v := range testKV {pMap.Store(k, v)}// 開始計時b.StartTimer()wg := sync.WaitGroup{}wg.Add(2)// 賦值go func() {// 對隨機key,賦值10萬次for i := 0; i < times; i++ {index := rand.Intn(times)pMap.Store(strconv.Itoa(index), index+1)}wg.Done()}()// 讀取go func() {// 對隨機key,讀取10萬次for i := 0; i < times; i++ {index := rand.Intn(times)pMap.Load(strconv.Itoa(index))}wg.Done()}()// 等待兩個協程處理完畢wg.Wait()} }

分段鎖map的實現源碼concurrentmap.go

package mainimport ("sync" )// 總的map type ConcurrentMap []*ConcurrentMapShared// 默認分片數 const SHARE_COUNT int = 64// 單個map分片 type ConcurrentMapShared struct {items map[string]interface{} // 本分片內的mapmu sync.RWMutex // 本分片的專用鎖 }// 新建一個map func NewConcurrentMap() *ConcurrentMap {m := make(ConcurrentMap, SHARE_COUNT)for i := 0; i < SHARE_COUNT; i++ {m[i] = &ConcurrentMapShared{items: map[string]interface{}{},}}return &m }// GetSharedMap 獲取key對應的map分片 func (m ConcurrentMap) GetSharedMap(key string) *ConcurrentMapShared {return m[uint(fnv32(key))%uint(SHARE_COUNT)] }// hash函數 func fnv32(key string) uint32 {hash := uint32(2166136261)prime32 := uint32(16777619)for i := 0; i < len(key); i++ {hash *= prime32hash ^= uint32(key[i])}return hash }// Set 設置key,value func (m ConcurrentMap) Set(key string, value interface{}) {sharedMap := m.GetSharedMap(key) // 找到對應的分片mapsharedMap.mu.Lock() // 加鎖(全鎖定)sharedMap.items[key] = value // 賦值sharedMap.mu.Unlock() // 解鎖 }// Get 獲取key對應的value func (m ConcurrentMap) Get(key string) (value interface{}, ok bool) {sharedMap := m.GetSharedMap(key) // 找到對應的分片mapsharedMap.mu.RLock() // 加鎖(讀鎖定)value, ok = sharedMap.items[key] // 取值sharedMap.mu.RUnlock() // 解鎖return value, ok }// Count 統計key個數 func (m ConcurrentMap) Count() int {count := 0for i := 0; i < SHARE_COUNT; i++ {m[i].mu.RLock() // 加鎖(讀鎖定)count += len(m[i].items)m[i].mu.RUnlock() // 解鎖}return count }// Keys1 所有的key方法1(方法:遍歷每個分片map,讀取key;缺點:量大時,阻塞時間較長) func (m ConcurrentMap) Keys1() []string {count := m.Count()keys := make([]string, count)// 遍歷所有的分片mapfor i := 0; i < SHARE_COUNT; i++ {m[i].mu.RLock() // 加鎖(讀鎖定)oneMapKeys := make([]string, len(m[i].items))for k := range m[i].items {oneMapKeys = append(oneMapKeys, k)}m[i].mu.RUnlock() // 解鎖// 匯總到keyskeys = append(keys, oneMapKeys...)}return keys }// Keys2 所有的key方法2(方法:開多個協程分別對分片map做統計再匯總 優點:量大時,阻塞時間較短) func (m ConcurrentMap) Keys2() []string {count := m.Count()keys := make([]string, count)ch := make(chan string, count) // 通道,遍歷時// 單獨起一個協程go func() {wg := sync.WaitGroup{}wg.Add(SHARE_COUNT)for i := 0; i < SHARE_COUNT; i++ {// 每個分片map,單獨起一個協程進行統計go func(ms *ConcurrentMapShared) {defer wg.Done()ms.mu.RLock() // 加鎖(讀鎖定)for k := range ms.items {ch <- k // 壓入通道}ms.mu.RUnlock() // 解鎖}(m[i])}// 等待所有協程執行完畢wg.Wait()close(ch) // 一定要關閉通道,因為不關閉的話,后面的range不會結束!!!}()// 遍歷通道,壓入所有的keyfor k := range ch {keys = append(keys, k)}return keys }

map+讀寫鎖的實現源碼mutexmap.go

package mainimport ("sync" )// 對外暴露的map type MutexMap struct {items map[string]interface{} // 為了和上面的ConcurrentMap做比較,都采用string->interface的方式mu *sync.RWMutex // 讀寫鎖 }// 新建一個map func NewMutexMap() *MutexMap {return &MutexMap{items: map[string]interface{}{},mu: new(sync.RWMutex),} }// Set 設置key,value func (m MutexMap) Set(key string, value interface{}) {m.mu.Lock() // 加鎖(全鎖定)m.items[key] = value // 賦值m.mu.Unlock() // 解鎖 }// Get 獲取key對應的value func (m MutexMap) Get(key string) (value interface{}, ok bool) {m.mu.RLock() // 加鎖(讀鎖定)value, ok = m.items[key] // 取值m.mu.RUnlock() // 解鎖return value, ok }// Count 統計key個數 func (m MutexMap) Count() int {m.mu.RLock() // 加鎖(讀鎖定)count := len(m.items)m.mu.RUnlock() // 解鎖return count }// Keys 所有的key func (m MutexMap) Keys() []string {m.mu.RLock() // 加鎖(讀鎖定)keys := make([]string, len(m.items))for k := range m.items {keys = append(keys, k)}m.mu.RUnlock() // 解鎖return keys }

?

總結

以上是生活随笔為你收集整理的go 分段锁ConcurrentMap,map+读写锁,sync.map的效率测试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。