[TOC]
### **map 使用注意的點,是否并發安全?**
map的類型是map\[key\],key類型的ke必須是可比較的,通常情況,會選擇內建的基本類型,比如整數、字符串做key的類型。如果要使用struct作為key,要保證struct對象在邏輯上是不可變的。在Go語言中,map\[key\]函數返回結果可以是一個值,也可以是兩個值。map是無序的,如果我們想要保證遍歷map時元素有序,可以使用輔助的數據結構,例如orderedmap。
**第一,**一定要先初始化,否則panic
**第二,**map類型是容易發生并發訪問問題的。不注意就容易發生程序運行時并發讀寫導致的panic。 Go語言內建的map對象不是線程安全的,并發讀寫的時候運行時會有檢查,遇到并發問題就會導致panic。
### **map 循環是有序的還是無序的**
無序的,map 因擴張?重新哈希時,各鍵值項存儲位置都可能會發生改變,順序自然也沒法保證
### **怎么處理對 map 進行并發訪問?有沒有其他方案**
1、直接加鎖,mutex
~~~
var mu sync.Mutex
mu.Lock()
//此處操作map
mu.Unlock()
~~~
2、sync.map ,底層也是加鎖了
~~~
// 并發安全的map
var m = sync.Map{}
func main() {
wg := sync.WaitGroup{}
// 對m執行20個并發的讀寫操作
for i := 0; i < 20; i++ {
wg.Add(1)
go func(n int) {
key := strconv.Itoa(n)
m.Store(key, n) // 存儲key-value
value, _ := m.Load(key) // 根據key取值
fmt.Printf("k=:%v,v:=%v\n", key, value)
wg.Done()
}(i)
}
wg.Wait()
}
~~~
3、RWMUTEX ,讀寫鎖
### **map 的數據結構是什么?是怎么實現擴容?**
>**了解一下:**
golang 中 map 是一個 kv 對集合。底層使用 hash table,用鏈表來解決沖突 ,出現沖突時,不是每一個 key 都申請一個結構通過鏈表串起來,而是以 bmap 為最小粒度掛載,一個 bmap 可以放 8 個 kv。在哈希函數的選擇上,會在程序啟動時,檢測 cpu 是否支持 aes,如果支持,則使用 aes hash,否則使用 memhash
```
type hmap struct {
count int // 元素的個數
B uint8 // buckets 數組的長度就是 2^B 個
overflow uint16 // 溢出桶的數量
?
buckets unsafe.Pointer // 2^B個桶對應的數組指針
oldbuckets unsafe.Pointer // 發生擴容時,記錄擴容前的buckets數組指針
?
extra *mapextra //用于保存溢出桶的地址
}
```
**map 的容量大小**
map 容量最多可容納 6.5*2^B 個元素,6.5 為裝載因子閾值常量。裝載因子的計算公式是:裝載因子=填入表中的元素個數/散列表的長度,裝載因子越大,說明空閑位置越少,沖突越多,散列表的性能會下降。
**擴容條件1**:**裝載因子 > 6.5**(源碼中定義的)
即元素過多超過最大容量
正常情況下,如果沒有溢出桶,那么一個桶中最多有8個元素,當平均每個桶中的數據超過了6.5個,那就意味著當前容量要不足了,發生擴容。
**擴容條件2**:**溢出桶的數量過多**
當 B < 15 時,如果overflow的bucket數量超過 2^B。
當 B >= 15 時,overflow的bucket數量超過 2^15。
### **slices能作為map類型的key嗎?**
不能
**不能作為map key 的類型包括:**
* slices
* maps
* functions
### **Golang Map 如何擴容?**
雙倍擴容:當前桶數組確實不夠用了,**發生這種擴容時,元素會重排,可能會發生桶遷移**,擴容采取了一種稱為“漸進式”的方式,原有的 key 并不會一 次性搬遷完畢,每次最多只會搬遷 2 個 bucket。
等量擴容:重新排列,極端情況下,重新排列也解決不了,map 存儲就會蛻 變成鏈表,性能大大降低,此時哈希因子 hash0 的設置,可以降低此類極 端場景的發生。**元素會發生重排,但不會換桶**
### **Map 增刪查到資料里**
- Go準備工作
- 依賴管理
- Go基礎
- 1、變量和常量
- 2、基本數據類型
- 3、運算符
- 4、流程控制
- 5、數組
- 數組聲明和初始化
- 遍歷
- 數組是值類型
- 6、切片
- 定義
- slice其他內容
- 7、map
- 8、函數
- 函數基礎
- 函數進階
- 9、指針
- 10、結構體
- 類型別名和自定義類型
- 結構體
- 11、接口
- 12、反射
- 13、并發
- 14、網絡編程
- 15、單元測試
- Go常用庫/包
- Context
- time
- strings/strconv
- file
- http
- Go常用第三方包
- Go優化
- Go問題排查
- Go框架
- 基礎知識點的思考
- 面試題
- 八股文
- 操作系統
- 整理一份資料
- interface
- array
- slice
- map
- MUTEX
- RWMUTEX
- Channel
- waitGroup
- context
- reflect
- gc
- GMP和CSP
- Select
- Docker
- 基本命令
- dockerfile
- docker-compose
- rpc和grpc
- consul和etcd
- ETCD
- consul
- gin
- 一些小點
- 樹
- K8s
- ES
- pprof
- mycat
- nginx
- 整理后的面試題
- 基礎
- Map
- Chan
- GC
- GMP
- 并發
- 內存
- 算法
- docker