golang key map 所有_Map的底層實現 為什么遍歷Map總是亂序的

Golang中Map的底層結構

其實提到Map,一般想到的底層實現就是哈希表,哈希表的結構主要是Hashcode + 數組。

  • 存儲kv時,首先將k通過hashcode后對數組長度取余,決定需要放入的數組的index
  • 當數組對應的index已有元素時,此時產生一個【哈希沖突】。一般來說哈希沖突的解決方式為鏈表法,即在沖突的位置生成一個鏈表來存儲元素

轉自:https://www.jianshu.com/p/7aafee109f28

參考:go語言中文文檔:www.topgoer.com

對于哈希表的具體實現和哈希沖突的解決方案這里就不贅述了,大家可以去看大神程序員小灰的漫畫:什么是HashMap?。

Redis中的Dict結構(用于實現RedisDB、Hashmap,Set等)其實就是非常典型的哈希表。Golang中的Map結構與傳統的哈希表稍有不同,它數組的基本單元并不是kv對,而是bucket。

每個bucket中可以放置8個kv對,這樣可以減少對象的數量,有利于提升GC的性能;當bucket中放置不下時,會繼續在溢出桶(overflow)中繼續存儲,串成一個鏈表的結構,如圖所示:

a6b72ca5bf71d99b0f752614c6dc3bae.png

鏈表法解決哈希沖突

Bucket中結構詳解

// map 哈希表type Hmap struct{         count int // 元素數量         ....         B uint8 // 哈希表數組的容量大小=2^B         ...         buckets unsafe.Pointer         oldBuckets unsafe.Pointer // 用于擴容         ...}// Bucket 桶type bmap struct{    tophash [8]uint8 // 哈希值的高8位    keys        values     overflow *bmap}
  1. key的哈希值的低B位(比如數組大小為32,2^5=32,則B=5)決定了它放入buckets中的index位置
  2. key的哈希值的高8位放入bucket中的tophash字段中,因為每個bucket中最多可以放8個KV對,所以tophash為大小為8的數組:tophash字段可以用于加速key的比較,當在一個bucket中查詢某key時,可以先比較哈希值的高8位是否符合,如果符合才會比較對應的key,這樣加速了key比較的過程;
  3. keys和values為分開存儲的,因為key和value可能是不同類型,比如map[int64]int8,分開存儲不需要進行字節補齊,可以節省空間;
  4. overflow即溢出桶,用于存儲哈希沖突后超過8對的kv對

擴容操作

負載因子=元素數量/數組大小
redis是1時擴容;golang因為數組中元素為bucket,每個bucket可以放8個kv,所以是在load factor = 6.5時才會觸發擴容邏輯:

  1. 擴容時容量翻倍,申請一個新的數組,采用漸進式哈希的方式進行遷移(和redis類似,可以避免影響性能)
  2. 遷移過程中支持讀寫:
  • 新增kv只寫新表
  • 修改和刪除雙寫,保證新老表中的數據一致
  • 讀取時優先讀老表,再讀新表
  1. 遷移過程為每次update/remove操作時觸發部分搬遷,每次搬遷2部分bucket中的數據:
  • 修改的key所在的當前Bucket
  • 按照順序搬遷的一個Bucket(避免某些bucket一直未被訪問導致無法搬遷成功)
  1. 直到所有數據搬遷完成后,刪除oldBuckets,使得老哈希表中的Bucket對象被GC回收

遍歷Map亂序之謎

在寫代碼時,當我們使用for k,v := range map {} 時會發現,每次輸出的kv都是亂序的,既然map的底層是數組為什么不能按照固定順序地輸出呢?

結合上文我們說到擴容流程,由于擴容過程會新申請一個數組,并且將keys重新rehash后放入新的數組中。那么新的數組中的key的順序就改變了,因此哈希表的底層實現使得map無法保證穩定地按照同一順序輸出keys。

Golang的作者為了”提醒“新手程序員不要依賴map遍歷時返回的key順序,采用隨機選擇遍歷起始位置的方式使得遍歷時返回是亂序的。

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

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

相關文章

樸素貝葉斯分類器 文本分類_構建災難響應的文本分類器

樸素貝葉斯分類器 文本分類背景 (Background) Following a disaster, typically you will get millions and millions of communications, either direct or via social media, right at the time when disaster response organizations have the least capacity to filter and…

第二輪沖次會議第六次

今天早上八點我們進行了站立會議 此次站立會議我們開了30分鐘 參加會議的人員: 黃睿麒 侯熙磊 會議內容:我們今天討論了如何分離界面,是在顯示上進行限制從而達到不同引用展現不同便簽信息,還是單獨開一個界面從而實現顯示不同界面…

markdown 鏈接跳轉到標題_我是如何使用 Vim 高效率寫 Markdown 的

本文僅適合于對vim有一定了解的人閱讀,沒有了解的人可以看看文中的視頻我使用 neovim 代替 vim ,有些插件是 neovim 獨占, neovim 和 vim 的區別請自行 google系統: Manjaro(Linux)前言之前我一直使用的是 vscode 和 typora 作為 markdown 編…

nginx運用

1、nginx的 命令 start nginx 這樣,nginx 服務就啟動了。打開任務管理器,查看 nginx.exe 進程,有二個進程會顯示,占用系統資源,那是相當的少。然后再打開瀏覽器,輸入 http://127.0.0.1/ 就可以看到nginx的…

數據修復案例

/*--數據修復案例 如何在數據庫文件損壞(日志文件完好)情況下,進行恢復 --(收藏整理)--*/ --測試步驟 --1.建一個測試數據庫test create database test go use test go -…

Seaborn:Python

Seaborn is a data visualization library built on top of matplotlib and closely integrated with pandas data structures in Python. Visualization is the central part of Seaborn which helps in exploration and understanding of data.Seaborn是建立在matplotlib之上…

利用日志還原數據庫

USE masterGO-- 創建測試數據庫CREATE DATABASE db_test GO -- 對數據庫進行備份BACKUP DATABASE db_testTO DISK c:/db_test.bakWITH FORMATGO -- 創建測試表CREATE TABLE db_test.dbo.tb_test( ID int) -- 延時 1 秒鐘,再進行后面的操作(這是由于SQL Server的時間精度…

Springboot集成BeanValidation擴展一:錯誤提示信息加公共模板

Bean Validator擴展 1、需求 ? 在使用validator時,有個需求就是公用錯誤提示信息,什么意思? 舉個例子: ? NotEmpty非空判斷,在資源文件中我不想每個非空判斷都寫”不能為空“,只需要寫”###“&#xff0c…

福大軟工 · 第十次作業 - 項目測評(團隊)

寫在前面 本次作業測試報告鏈接林燊大哥第一部分 調研,評測 一、評測 軟件的bug,功能評測,黑箱測試 1.下載并使用,描述最簡單直觀的個人第一次上手體驗 IOS端 UI界面簡單明了,是我喜歡的極簡風格。課程模塊界面簡潔優雅…

銷貨清單數據_2020年8月數據科學閱讀清單

銷貨清單數據Note: I am not affiliated with any of the writers in this article. These are simply books and essays that I’m excited to share with you. There are no referrals or a cent going in my pocket from the authors or publishers mentioned. Reading is a…

c++運行不出結果_fastjson 不出網利用總結

點擊藍字 關注我們 聲明 本文作者:flashine 本文字數:2382 閱讀時長:20分鐘 附件/鏈接:點擊查看原文下載 聲明:請勿用作違法用途,否則后果自負 本文屬于WgpSec原創獎勵計劃,未經許可禁止轉載 前言 之前做項目在內網測到了一個fastjson反序列化漏洞,使用dnslo…

FocusBI:租房分析可視化(PowerBI網址體驗)

微信公眾號:FocusBI關注可了解更多的商業智能、數據倉庫、數據庫開發、爬蟲知識及滬深股市數據推送。問題或建議,請關注公眾號發送消息留言;如果你覺得FocusBI對你有幫助,歡迎轉發朋友圈或在文章末尾點贊[1] 《商業智能教程》pdf下載地址 …

米其林餐廳 鹽之花_在世界范圍內探索《米其林指南》

米其林餐廳 鹽之花Among the culinary world, there are few greater accolades for a restaurant than being awarded a Michelin star (or three!), or being listed as one of the best in the world by a reputable guide. Foodies and fine dine lovers like myself, see …

require_once的用法

require_once 語句和 require 語句完全相同,唯一區別是 PHP 會檢查該文件是否已經被包含過,如果是則不會再次包含。 參見 include_once 的文檔來理解 _once 的含義,并理解與沒有 _once 時候有什么不同。 有一個文件a.php,里面有一個變量$var1…

差值平方和匹配_純前端實現圖片的模板匹配

基礎介紹模板匹配是指在當前圖像A里尋找與圖像B最相似的部分,本文中將圖像A稱為模板圖像,將圖像B稱為搜索匹配圖像。引言:一般在Opencv里實現此種功能非常方便:直接調用result cv2.matchTemplate(templ, search, method)templ 為…

藍牙耳機音量大解決辦法_長時間使用藍牙耳機的危害這么大?我們到底該選什么藍牙耳機呢?...

藍牙耳機避免了耳機線纏結,使人活動更自由,給人們帶來了更加方便、舒適的聽覺體驗。但近日,英國《每日郵報》刊文表示,藍牙耳機可能會危害人體健康。美國加州大學伯克利分校公共健康教授喬爾莫斯科維茨博士表示,已有研…

JVM基礎系列第10講:垃圾回收的幾種類型

我們經常會聽到許多垃圾回收的術語,例如:Minor GC、Major GC、Young GC、Old GC、Full GC、Stop-The-World 等。但這些 GC 術語到底指的是什么,它們之間的區別到底是什么?今天我們就來詳細說說。 Minor GC 從年輕代空間回收內存被…

模擬退火學習

模擬退火學習 作業部落網上講的不錯的(他好像還有一些其他的東西、、、) 引入 對于一些題目,無法直接算出答案或者想不到正解,想到隨機找答案,那么模擬退火就是一種有系統方法的隨機算法 沒用的不需要了解的來源 百度百科...... 模擬退火算法…

spotify 數據分析_我的Spotify流歷史分析

spotify 數據分析Spotisis /spo-ti-sis/ noun The analysis of one’s Spotify streaming history using Python.Spotisis / spo-ti-sis / 名詞使用Python分析一個人的Spotify流歷史。 I was reading through a lot of data science related guides and project ideas when I …

idea 搜索不到gsonformat_Idea中GsonFormat插件安裝

這個教不的期是范添事大部會基近說小間進圍磚本的程主要是學習IntelliJ IDEA 如何通過GsonFormat插件將JSONObject格式的String 支器事的后功發久這含層請間業在屏有隨些氣和域,實按控幻近持的前時來能過后些的處求也務瀏蔽等機站風滾或默現鈕制燈近持的前時來能過后…