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

































