Go 為什么不在語言層面支持 Map 并發(fā)?
本文轉(zhuǎn)載自微信公眾號「腦子進(jìn)煎魚了」,作者陳煎魚 。轉(zhuǎn)載本文請聯(lián)系腦子進(jìn)煎魚了公眾號。
大家好,我是煎魚。
很多小伙伴學(xué)習(xí) Go 語言的語法時,可能只是輕輕地看到過這個問題,結(jié)果一旦上手,多多少少一個組內(nèi)總會碰到過幾次(我經(jīng)常見到...)。
甚至?xí)l(fā)現(xiàn)有一定年限的程序員也會遇到。有小伙伴疑惑了,這么折騰,為什么 Go 不直接在語言層面就支持 map 并發(fā),直接無腦用。
那得有多香?
為什么原生不支持
憑什么 Go 官方還不支持,難不成太復(fù)雜了,性能太差了,到底是為什么?
官方答復(fù)原因如下(via @go faq):
- 典型使用場景:map 的典型使用場景是不需要從多個 goroutine 中進(jìn)行安全訪問。
- 非典型場景(需要原子操作):map 可能是一些更大的數(shù)據(jù)結(jié)構(gòu)或已經(jīng)同步的計算的一部分。
- 性能場景考慮:若是只是為少數(shù)程序增加安全性,導(dǎo)致 map 所有的操作都要處理 mutex,將會降低大多數(shù)程序的性能。
核心來講就是:Go 團隊在經(jīng)過了長時間的討論后,認(rèn)為原生 map 更應(yīng)適配典型使用場景。
如果為了小部分情況,將會導(dǎo)致大部分程序付出性能代價,決定了不支持原生的并發(fā) map 讀寫。且在 Go1.6 起,增加了檢測機制,并發(fā)的話會導(dǎo)致異常。
為什么要崩潰
前面有提到一點,在 Go1.6 起會進(jìn)行原生 map 的并發(fā)檢測,這是一些人的 “噩夢”。
在此有人吐槽到:“明明給我拋個錯就好了,憑什么要讓我的 Go 進(jìn)程直接崩潰掉,分分鐘給我背個 P0”。
場景枚舉
這里我們假設(shè)一下,如果并發(fā)讀寫 map 是以下兩種場景:
產(chǎn)生 panic:程序 panic -> 默認(rèn)走進(jìn) recover -> 沒有對并發(fā) map 進(jìn)行處理 -> map 存在臟數(shù)據(jù) -> 程序使用臟數(shù)據(jù) -> 產(chǎn)生**未知((影響。
產(chǎn)生 crash:程序 crash -> 直接崩潰 -> 保全數(shù)據(jù)(數(shù)據(jù)正常)-> 產(chǎn)生**明確((風(fēng)險。
你會選擇哪一種方案呢?Go 官方在兩者的風(fēng)險衡量中選擇了第二種。
無論是編程,還是人生。如何在隨機性中掌握確定性的部分,也是一門極大的哲學(xué)了。
let it crash
Go 官方團隊選擇的方式是業(yè)內(nèi)經(jīng)典的 “let it crash” 行為,很多編程語言中,都會將其奉行為設(shè)計哲學(xué)。
let it crash 是指工程師不必過分擔(dān)心未知的錯誤,而去進(jìn)行面面俱到的防御性編碼。
這塊理念最經(jīng)典的就是 erlang 了。
總結(jié)
在今天這篇文章中,我們介紹了 Go 語言為什么不支持原生支持 map 并發(fā),核心原因是大部分場景都不需要,從性能考慮上做的考慮。
直接讓并發(fā)讀寫 map 的原因,是從 “let it crash” 去考慮。這塊如果你想在自己的工程中避免這個情況,可以在 linter 等工具鏈加入競態(tài)檢測(-race),也可以避免這類風(fēng)險。
你覺得 Go 這塊的設(shè)計考慮怎么樣呢?

































