首頁 後端開發 Golang golang map 實作原理

golang map 實作原理

May 15, 2023 am 11:59 AM

在學習 Golang 的過程中,map 是我們常用的一種資料結構,可以用來儲存 key-value 對。但是,你是否想過 map 的實作原理是什麼呢?在本文中,我們將探究 Golang 中 map 的實作原理。

map 實作原理簡介

map 其實是一個雜湊表,它的實作原理就是雜湊演算法。哈希表是一種根據關鍵字直接存取記憶體儲存位置的資料結構,也就是說,它提供了一種將關鍵字映射到記憶體位址的方法。在哈希表中,關鍵字被稱為“鍵”,透過雜湊函數計算得到的記憶體位址稱為“桶”,桶儲存了鍵值對。

在Golang 中,map 是透過在桶記憶體區域儲存鍵值對實現的,每個桶都有一個頭部結構體,用於描述桶的狀態,這個頭部結構體稱為“ bucket」。

bucket 資料結構

先來看看bucket 的資料結構:

type bmap struct {
    tophash [bucketCnt]uint8
    // data 的类型在 map 被分配空间的时候由 map 的 key 和 value 类型决定
    // 如果 key 类型和 value 类型都是未知类型,那么 data 的类型是 byte
    // 因为 byte 可以用于存储任何类型,也就是说 data 可以存储任何类型的 key 和 value
    // 在存储 key 和 value 的时候,需要将 key 和 value 转换成 uintptr,然后再转换成 byte 存储到 data 中
    // 读取 key 和 value 的时候反向操作即可
    // 因此,map 中的 key 和 value 一般都是需要转换成 uintptr 类型的
    // 这里我们可以简单地理解为 data 存储了键值对的二进制数据
    // 第一个 bucket 中如果存不下某个 key-value,还需要在第二个 bucket 中存储
    // 所以,data 的长度可以为 1 或 2
    // 当 data 的长度为 1 或 2 时,存储的键值对的个数分别为 1 或 2
    // 因此,bucket 中最多只能存储 8 个键值对
    // 否则,就需要将键值对存储在 overflow 中
    // overflow 是一个指向单链表头部的指针数组
    // 如果某个桶存储的键值对数量超过了 8,那么就将多余的键值对存储到 overflow 中
    // overflow 中的第一个 bucket 中也是能够存储 8 个键值对的,如果第一个 bucket 中存不下的话
    // 那么还需要在第二个 bucket 中继续存储
    // 所以,overflow 数组的长度也可以为 1 或 2
    // 当 overflow 数组长度为 1 或 2 时,最多存储 8 个键值对的 overflow
    // 当 overflow 数组长度为 3 时,最多存储 24 个键值对的 overflow
    // 也就是说,如果 map 中存储的键值对数量很多的话,那么可能会有很多个 overflow 桶
    // 而 overflow 数组是动态分配的,因此它的长度是不定的,只有在运行时才能确定
    data unsafe.Pointer
    // overflow 是一个指针数组,用于存储除当前桶以外的其它桶
    // 如果某个桶的键值对数量超过了 8,那么它会将多余的键值对存储到 overflow 中
    // overflow 数组中的每个元素都是一个 bucket 指针
    // 这些 bucket 指针构成了一个链表,也就是所谓的 overflow 链表
    overflow *[]*bmap
    // 这里存储的是这个 bucket 当前存储的键值对的个数
    count int16
    // flags 存储了 bucket 的标志
    // 一个 bucket 可能会有如下三种状态:
    // 1. empty,表示这个 bucket 没有存储任何键值对
    // 2. iterator,表示这个 bucket 正在被访问,不能再被其它操作使用
    // 3. deleted,表示这个 bucket 存储的键值对已经被删除了
    // 注意,该标志位只有在 GC 达到一定阈值后才会被置为 true,而且并不是立即删除键值对,而是在下一次 GC 的时候才会内存回收
    flags uint8
    // Bmap 的类型标记
    // Bmap 用来标识存储于上文中 data 指针中的数据类型
    // 如果 data 中存储的是 int,那么 Bmap 的值为 hmap.BmapInt
    // 如果 data 中存储的是 string,那么 Bmap 的值为 hmap.BmapString
    // 如果 data 中存储的是 interface{},那么 Bmap 的值为 hmap.BmapInterface
    // 如果 data 中存储其他类型,那么 Bmap 的值为 hmap.BmapOther
    BmapType uint16
    // 与该 bucket 相关联的 key 的类型
    tophash0 uint8
}
登入後複製

從上面的定義中,我們可以看到,bucket 儲存了以下資訊:

  • tophash:用於快速篩選出不匹配的key;
  • data:儲存鍵值對的資料;
  • overflow:儲存overflow 鍊錶的指標陣列;
  • count:儲存了目前bucket 中儲存的鍵值對的個數,最多為8;
  • flags:儲存了bucket 的一些狀態資訊;
  • BmapType:存儲了data 中儲存資料的型別;
  • tophash0:與該bucket 相關聯的key 的型別。

實作原理

由於map 儲存的資料是鍵值對,而且鍵值對的key 值是不可重複的並且能夠進行比較大小操作,我們可以採用哈希函數將key 值轉換為唯一的雜湊值,然後將雜湊值作為key 值對應的索引,將value 值儲存在該索引上。

在Golang 中,每個map 都有一個哈希表,這個哈希表實際上就是一段連續的儲存空間,可以儲存若干個桶(bucket),每個桶都是一個bucket 類型的結構體。

那麼雜湊表的大小是如何決定的呢?它是在 map 創建時動態分配記憶體而來的,首次分配空間時候使用的預設大小為 8 個桶。如果第一次增加元素的時候,桶的數量不夠,則雜湊表的大小會擴容,並重新計算每個元素在雜湊表中的索引位置。

在 Golang 中,雜湊函數的作用主要是將 key 值雜湊化,使其更方便的定位到雜湊表中的一個桶,從而加速查找 key 值對應的 value 值。在 Golang 中,雜湊函數的實作採用了 MurmurHash3 演算法。

由於雜湊函數是將 key 對應到整數,因此不同的 key 值可能會對應到相同的索引。這種情況被稱為哈希衝突。當出現雜湊衝突時,Golang 採用鍊錶法來解決,將相同索引上的鍵值對儲存在該索引的鍊錶中,這些鍵值對就稱為 overflow。

總結

Golang 的 map 實作原理主要依賴雜湊表和雜湊函數。哈希函數用於散列化 key 值,將其映射到哈希表中的一個桶,從而加速查找 value 值的操作。雜湊表由若干個桶組成,每個桶由一個 bucket 類型的結構體表示,儲存了鍵值對的資訊。當哈希表中的相同索引位置上存在多個鍵值對時,採用鍊錶法儲存 overflow。 Golang 中的 map 其實就是一個動態哈希表,可以動態地調整哈希表的大小。在使用 map 時,需要注意避免哈希衝突和包含無法比較大小的類型作為 key。

以上是golang map 實作原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
Golang vs. Python:性能和可伸縮性 Golang vs. Python:性能和可伸縮性 Apr 19, 2025 am 12:18 AM

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

Golang和C:並發與原始速度 Golang和C:並發與原始速度 Apr 21, 2025 am 12:16 AM

Golang在並發性上優於C ,而C 在原始速度上優於Golang。 1)Golang通過goroutine和channel實現高效並發,適合處理大量並發任務。 2)C 通過編譯器優化和標準庫,提供接近硬件的高性能,適合需要極致優化的應用。

Golang的影響:速度,效率和簡單性 Golang的影響:速度,效率和簡單性 Apr 14, 2025 am 12:11 AM

goimpactsdevelopmentpositationality throughspeed,效率和模擬性。 1)速度:gocompilesquicklyandrunseff,IdealforlargeProjects.2)效率:效率:ITScomprehenSevestAndardArdardArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdEcceSteral Depentencies,增強的Depleflovelmentimency.3)簡單性。

開始GO:初學者指南 開始GO:初學者指南 Apr 26, 2025 am 12:21 AM

goisidealforbeginnersandsubableforforcloudnetworkservicesduetoitssimplicity,效率和concurrencyFeatures.1)installgromtheofficialwebsitealwebsiteandverifywith'.2)

Golang vs.C:性能和速度比較 Golang vs.C:性能和速度比較 Apr 21, 2025 am 12:13 AM

Golang適合快速開發和並發場景,C 適用於需要極致性能和低級控制的場景。 1)Golang通過垃圾回收和並發機制提升性能,適合高並發Web服務開發。 2)C 通過手動內存管理和編譯器優化達到極致性能,適用於嵌入式系統開發。

Golang vs. Python:主要差異和相似之處 Golang vs. Python:主要差異和相似之處 Apr 17, 2025 am 12:15 AM

Golang和Python各有优势:Golang适合高性能和并发编程,Python适用于数据科学和Web开发。Golang以其并发模型和高效性能著称,Python则以简洁语法和丰富库生态系统著称。

Golang和C:性能的權衡 Golang和C:性能的權衡 Apr 17, 2025 am 12:18 AM

Golang和C 在性能上的差異主要體現在內存管理、編譯優化和運行時效率等方面。 1)Golang的垃圾回收機制方便但可能影響性能,2)C 的手動內存管理和編譯器優化在遞歸計算中表現更為高效。

C和Golang:表演至關重要時 C和Golang:表演至關重要時 Apr 13, 2025 am 12:11 AM

C 更適合需要直接控制硬件資源和高性能優化的場景,而Golang更適合需要快速開發和高並發處理的場景。 1.C 的優勢在於其接近硬件的特性和高度的優化能力,適合遊戲開發等高性能需求。 2.Golang的優勢在於其簡潔的語法和天然的並發支持,適合高並發服務開發。

See all articles