var m1 map[string]string fmt.Println(m1["1"])
panic: assignment to entry in nil map
var m1 map[string]string m1["1"] = "1"
通過(guò)fmt打印map時(shí),空map和nil map結(jié)果是一樣的,都為map[]。所以,這個(gè)時(shí)候別斷定map是空還是nil,而應(yīng)該通過(guò)map == nil來(lái)判斷。
補(bǔ)充:Golang清空map的兩種方式及性能比拼
a := make(map[string]int) a["a"] = 1 a["b"] = 2 // clear all a = make(map[string]int)
通過(guò)Go的內(nèi)部函數(shù)mapclear方法刪除。這個(gè)函數(shù)并沒(méi)有顯示的調(diào)用方法,當(dāng)你使用for循環(huán)遍歷刪除所有元素時(shí),Go的編譯器會(huì)優(yōu)化成Go內(nèi)部函數(shù)mapclear。
package main func main() { m := make(map[byte]int) m[1] = 1 m[2] = 2 for k := range m { delete(m, k) } }
把上述源代碼直接編譯成匯編(默認(rèn)編譯是會(huì)優(yōu)化的):
go tool compile -S map_clear.go
可以看到編譯器把源碼9行的for循環(huán)直接優(yōu)化成了mapclear去刪除所有元素。如下:
再來(lái)看看關(guān)閉優(yōu)化后的結(jié)果:
go tool compile -l -N -S map_clear.go
關(guān)閉優(yōu)化選項(xiàng)后,Go編譯器直接通過(guò)循環(huán)遍歷來(lái)刪除map里面的元素。
具體的mapclear代碼可以在go源碼庫(kù)中runtime/map.go文件中看到,代碼如下:
// mapclear deletes all keys from a map. func mapclear(t *maptype, h *hmap) { if raceenabled h != nil { callerpc := getcallerpc() pc := funcPC(mapclear) racewritepc(unsafe.Pointer(h), callerpc, pc) } if h == nil || h.count == 0 { return } if h.flagshashWriting != 0 { throw("concurrent map writes") } h.flags ^= hashWriting h.flags ^= sameSizeGrow h.oldbuckets = nil h.nevacuate = 0 h.noverflow = 0 h.count = 0 // Keep the mapextra allocation but clear any extra information. if h.extra != nil { *h.extra = mapextra{} } // makeBucketArray clears the memory pointed to by h.buckets // and recovers any overflow buckets by generating them // as if h.buckets was newly alloced. _, nextOverflow := makeBucketArray(t, h.B, h.buckets) if nextOverflow != nil { // If overflow buckets are created then h.extra // will have been allocated during initial bucket creation. h.extra.nextOverflow = nextOverflow } if h.flagshashWriting == 0 { throw("concurrent map writes") } h.flags ^= hashWriting }
benchmark代碼如下:
func BenchmarkMakeNewMap(b *testing.B) { tmpMap := make(map[string]string, 10000) for i := 0; i b.N; i++ { for j := 0; j 10000; j++ { tmpMap["tmp"+strconv.Itoa(j)] = "tmp" } tmpMap = make(map[string]string, 10000) } } func BenchmarkDeleteMap(b *testing.B) { tmpMap := make(map[string]string, 10000) for i := 0; i b.N; i++ { for j := 0; j 10000; j++ { tmpMap["tmp"+strconv.Itoa(j)] = "tmp" } for k := range tmpMap { delete(tmpMap, k) } } }
得到測(cè)試結(jié)果如下:
從測(cè)試結(jié)果上看,好像確實(shí)delete的方式效率更高,但是這個(gè)benchmark中總感覺(jué)沒(méi)有測(cè)試到真正清空map的地方,中間穿插著put map的操作,我們用方法2再測(cè)一下。
UT代碼如下:
測(cè)試過(guò)程中禁用了gc,避免gc對(duì)運(yùn)行時(shí)間和內(nèi)存產(chǎn)生干擾。
func TestMakeNewMap(t *testing.T) { debug.SetGCPercent(-1) var m runtime.MemStats tmpMap := make(map[string]string, 1000000) for j := 0; j 1000000; j++ { tmpMap["tmp"+strconv.Itoa(j)] = "tmp" } start := time.Now() tmpMap = make(map[string]string, 1000000) fmt.Println(time.Since(start).Microseconds()) runtime.ReadMemStats(m) fmt.Printf("%d Kb\n", m.Alloc/1024) } func TestDeleteMap(t *testing.T) { debug.SetGCPercent(-1) var m runtime.MemStats tmpMap2 := make(map[string]string, 1000000) for j := 0; j 1000000; j++ { tmpMap2["tmp"+strconv.Itoa(j)] = "tmp" } start := time.Now() for k := range tmpMap2 { delete(tmpMap2, k) } fmt.Println(time.Since(start).Microseconds()) runtime.ReadMemStats(m) fmt.Printf("%d Kb\n", m.Alloc/1024) }
測(cè)試結(jié)果如下:
從測(cè)試結(jié)果上看,好像確實(shí)是make方式的效率更低,而且內(nèi)存占用更多,但結(jié)果真的是這樣嗎?
我們把make方式的make map的大小改為0再試一下:
tmpMap = make(map[string]string)
得到如下結(jié)果,What?時(shí)間為0了,內(nèi)存消耗也跟delete的方式一樣:
我們把make方式的make map的大小改為10000再試一下:
tmpMap = make(map[string]string, 10000)
結(jié)果如下:
通過(guò)上面的測(cè)試,可以得出結(jié)論:
1、在map的數(shù)量級(jí)在10w以內(nèi)的話,make方式會(huì)比delete方式速度更快,但是內(nèi)存會(huì)消耗更多一點(diǎn)。
2、如果map數(shù)量級(jí)大于10w的話,delete的速度會(huì)更快,且內(nèi)存消耗更少。
3、對(duì)于不再使用的map,直接使用make方式,長(zhǎng)度為0清空更快。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
標(biāo)簽:雞西 欽州 汕頭 梅河口 重慶 銅川 吐魯番 蘭州
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Golang 空map和未初始化map的注意事項(xiàng)說(shuō)明》,本文關(guān)鍵詞 Golang,空,map,和,未,初始化,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。