《Go小技巧易錯點100例》第三十二篇

本期分享:

1.sync.Map的原理和使用方式

2.實現有序的Map

sync.Map的原理和使用方式

sync.Map的底層結構是通過讀寫分離無鎖讀設計實現高并發安全:

1)雙存儲結構

包含原子化的 read(只讀緩存,無鎖快速訪問)和加鎖的 dirty(寫入緩沖區)

2)讀優先

讀取時先嘗試無鎖訪問 read,未命中時加鎖訪問 dirty 并記錄未命中次數

3)動態升級

當未命中次數超過 dirty 長度時,將 dirty 原子替換為新的 read

4)延遲刪除

刪除操作僅標記數據狀態(expunged),實際清理在 dirty 升級時批量處理

5)值原子化

通過 entry 指針的原子操作實現值更新的無鎖化,適用于讀多寫少的高并發場景。

請在此添加圖片描述

部分源碼:

type Map struct {mu     sync.Mutex       // 保護 dirty 操作read   atomic.Value     // 只讀緩存(atomic 訪問)dirty  map[interface{}]*entry  // 寫入緩沖區misses int              // read 未命中計數器
}type entry struct {p unsafe.Pointer  // 可能的狀態:nil, expunged, 有效指針
}

Go 語言標準庫中的 sync.map 專為以下場景優化:

  • 讀多寫少(98% 讀操作)
  • 動態鍵空間(頻繁創建/刪除鍵)
  • 需要保證并發安全

性能對比測試: 測試場景為4核CPU環境下并發讀寫

實現方式100萬次讀/寫 (ns/op)內存占用 (MB)
map+sync.RWMutex42032
sync.Map8528

實現有序的map

在Go語言中,標準庫的map是無序的,但可以通過組合數據結構實現有序映射。以下是幾種常見實現方案,根據需求選擇最適合的方式:

方案一:維護插入順序(鏈表法)
package mainimport"fmt"type OrderedMap struct {items map[interface{}]interface{}order []interface{}
}func NewOrderedMap() *OrderedMap {return &OrderedMap{items: make(map[interface{}]interface{}),order: make([]interface{}, 0),}
}func (m *OrderedMap) Set(key, value interface{}) {if _, exists := m.items[key]; !exists {m.order = append(m.order, key)}m.items[key] = value
}func (m *OrderedMap) Get(key interface{}) (interface{}, bool) {val, exists := m.items[key]return val, exists
}func (m *OrderedMap) Delete(key interface{}) {delete(m.items, key)// 重建順序切片(簡單實現,實際可用更高效方式)newOrder := make([]interface{}, 0, len(m.order)-1)for _, k := range m.order {if k != key {newOrder = append(newOrder, k)}}m.order = newOrder
}func (m *OrderedMap) Iterate() {for _, key := range m.order {fmt.Printf("%v: %v\n", key, m.items[key])}
}
方案二:排序映射(使用sort包)
package mainimport ("fmt""sort"
)type SortedMap struct {keys  []intitems map[int]string
}func NewSortedMap() *SortedMap {return &SortedMap{keys:  make([]int, 0),items: make(map[int]string),}
}func (m *SortedMap) Set(key int, value string) {if _, exists := m.items[key]; !exists {m.keys = append(m.keys, key)sort.Ints(m.keys) // 保持有序}m.items[key] = value
}func (m *SortedMap) Get(key int) (string, bool) {val, exists := m.items[key]return val, exists
}func (m *SortedMap) Iterate() {for _, key := range m.keys {fmt.Printf("%d: %s\n", key, m.items[key])}
}
方案三:使用第三方庫(推薦)
import "github.com/emirpasic/gods/maps/treemap"func main() {// 自然排序m := treemap.NewWithIntComparator()m.Put(1, "one")m.Put(3, "three")m.Put(2, "two")// 迭代器it := m.Iterator()for it.Next() {fmt.Printf("%d: %s\n", it.Key(), it.Value())}// 反向迭代rit := m.ReverseIterator()for rit.Next() {fmt.Printf("%d: %s\n", rit.Key(), rit.Value())}
}

本篇結束~

歡迎關注我

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82584.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82584.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82584.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL】行結構詳解:InnoDb支持格式、如何存儲、頭信息區域、Null列表、變長字段以及與其他格式的對比

📢博客主頁:https://blog.csdn.net/2301_779549673 📢博客倉庫:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢歡迎點贊 👍 收藏 ?留言 📝 如有錯誤敬請指正! &…

LabVIEW多通道并行數據存儲系統

在工業自動化監測、航空航天測試、生物醫學信號采集等領域,常常需要對多個傳感器通道的數據進行同步采集,并根據后續分析需求以不同采樣率保存特定通道組合。傳統單線程數據存儲方案難以滿足實時性和資源利用效率的要求,因此設計一個高效的多…

【Linux系列】bash_profile 與 zshrc 的編輯與加載

💝💝💝歡迎來到我的博客,很高興能夠在這里和您見面!希望您在這里可以感受到一份輕松愉快的氛圍,不僅可以獲得有趣的內容和知識,也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

針對Mkdocs部署到Githubpages加速訪問速度的一些心得

加速網站訪問的一些心得 在使用 MkDocs 構建網站時,為了提高訪問速度,我們可以采取以下一些措施: 1. 優化圖片 使用合適的圖片格式,如 WebP、JPEG2000 等,減少圖片文件大小,從而加快加載速度。 可以使用…

Mysql中切割字符串作為in的查詢條件

問題:需要將一個字符串切割成數組作為in的查詢條件,如: select * from table_1 where name in (select slit(names) from table_2 where id 3); names 返回的格式是’name1,name2,name3…,需要將name按照逗號切割作為in的查詢條件&#xff1b…

云計算中的虛擬化:成本節省、可擴展性與災難恢復的完美結合

云計算中虛擬化的 4 大優勢 1. 成本效益 從本質上講,虛擬化最大限度地減少了硬件蔓延。團隊可以將多個虛擬機整合到單個物理主機上,而不是為每個工作負載部署單獨的服務器。這大大減少了前期硬件投資和持續維護。 結果如何?更低的功耗、更低…

Linux : 多線程【線程概念】

Linux : 多線程【線程概念】 (一)線程概念線程是什么用戶層的線程linux中PID與LWP的關系 (二) 進程地址空間頁表(三) 線程總結線程的優點線程的缺點線程異常線程用途 (一)線程概念 線程是什么 在一個程序里的一個執行…

IDEA轉戰TREA AI IDE : springboot+maven+vue項目配置

一、trea下載安裝 Trae官方網址: https://www.trae.com.cn/ Trae官方文檔:https://docs.trae.com.cn/docs/what-is-trae?_langzh w3cschool: https://www.w3cschool.cn/traedocs/ai-settings.html 安裝這里省略,正常安裝即可。…

Java--圖書管理系統(簡易版)

目錄 目錄 前言 🔔1.library包 1.1 Book類 1.2 BookList類 🔔2.user包 2.1User類(父類) 2.2Admin(管理員) 2.3 NormalUser(普通用戶) 🔔3.Operation包 🕐3.1 IOperation接口 🕑3.2ListOperation(查看操作)…

深入淺出:Spring Boot 中 RestTemplate 的完整使用指南

在分布式系統開發中,服務間通信是常見需求。作為 Spring 框架的重要組件,RestTemplate 為開發者提供了簡潔優雅的 HTTP 客戶端解決方案。本文將從零開始講解 RestTemplate 的核心用法,并附贈真實地圖 API 對接案例。 一、環境準備 在 Spring…

大數據處理利器:Hadoop 入門指南

一、Hadoop 是什么?—— 分布式計算的基石 在大數據時代,處理海量數據需要強大的技術支撐,Hadoop 應運而生。Apache Hadoop 是一個開源的分布式計算框架,致力于為大規模數據集提供可靠、可擴展的分布式處理能力。其核心設計理念是…

685SJBH計量管理系統

摘 要 計量,在我國已有五千年的歷史。計量的發展與社會進步聯系在一起,它是人類文明的重要組成部分。它的發展經歷了古典階段、經典階段和現代階段。而企業的計量管理是對測量數據、測量過程和測量設備的管理。 本系統通過分析現有計量系統的業務邏輯…

從0到1構建前端監控系統:錯誤捕獲、性能采集、用戶體驗全鏈路追蹤實戰指南SDK實現

目錄 前言為什么要做前端監控前端監控目標穩定性用戶體驗業務 前端監控流程常見埋點方案代碼埋點可視化埋點無痕埋點 創建項目第一步、創建monitor文件,cmd進入文件進行npm init -y 項目初始化第二步、創建src/index.js和src/index.html文件第三步、創建webpack.con…

前端瀏覽器判斷設備類型的方法

前端瀏覽器判斷設備類型的方法 在前端開發中,判斷設備類型(如手機、平板、桌面電腦)有多種方法,以下是常用的幾種方式: 1. 使用 User Agent 檢測 通過 navigator.userAgent 獲取用戶代理字符串進行判斷:…

MNIST 手寫數字分類

轉自我的個人博客: https://shar-pen.github.io/2025/05/04/torch-distributed-series/1.MNIST/ 基礎的單卡訓練 本筆記本演示了訓練一個卷積神經網絡(CNN)來對 MNIST 數據集中的手寫數字進行分類的過程。工作流程包括: 數據準備&#xff…

數據庫中的 Segment、Extent、Page、Row 詳解

在關系型數據庫的底層存儲架構中,數據并不是隨意寫入磁盤,而是按照一定的結構分層管理的。理解這些存儲單位對于優化數據庫性能、理解 SQL 執行過程以及排查性能問題都具有重要意義。 我將從宏觀到微觀,依次介紹數據庫存儲中的四個核心概念&…

DAMA車輪圖

DAMA車輪圖是國際數據管理協會(DAMA International)提出的數據管理知識體系(DMBOK)的圖形化表示,它以車輪(同心圓)的形式展示了數據管理的核心領域及其相互關系。以下是基于用戶提供的關鍵詞對D…

《QDebug 2025年4月》

一、Qt Widgets 問題交流 1. 二、Qt Quick 問題交流 1.QML單例動態創建的對象,訪問外部id提示undefined 先定義一個窗口組件,打印外部的id: // MyWindow.qml import QtQuick 2.15 import QtQuick.Window 2.15Window {id: controlwidth: …

JS | 正則 · 常用正則表達式速查表

以下是前端開發中常用的正則表達式速查表,包含驗證規則、用途說明與示例: 📌 常用正則表達式速查表 名稱正則表達式描述 / 用途示例手機號/^1[3-9]\d{9}$/中國大陸手機號13812345678 ?座機號/^0\d{2,3}-?\d{7,8}$/固定電話010-12345678 ?…