Go 爲什麼不在語言層面支持 map 併發?
大家好,我是煎魚。
很多小夥伴學習 Go 語言的語法時,可能只是輕輕地看到過這個問題,結果一旦上手,多多少少一個組內總會碰到過幾次(我經常見到...)。
甚至會發現有一定年限的程序員也會遇到。有小夥伴疑惑了,這麼折騰,爲什麼 Go 不直接在語言層面就支持 map 併發,直接無腦用。
那得有多香?
爲什麼原生不支持
憑什麼 Go 官方還不支持,難不成太複雜了,性能太差了,到底是爲什麼?
官方答覆原因如下(via @go faq):
-
典型使用場景:map 的典型使用場景是不需要從多個 goroutine 中進行安全訪問。
-
非典型場景(需要原子操作):map 可能是一些更大的數據結構或已經同步的計算的一部分。
-
性能場景考慮:若是隻是爲少數程序增加安全性,導致 map 所有的操作都要處理 mutex,將會降低大多數程序的性能。
核心來講就是:Go 團隊在經過了長時間的討論後,認爲原生 map 更應適配典型使用場景。
如果爲了小部分情況,將會導致大部分程序付出性能代價,決定了不支持原生的併發 map 讀寫。且在 Go1.6 起,增加了檢測機制,併發的話會導致異常。
爲什麼要崩潰
前面有提到一點,在 Go1.6 起會進行原生 map 的併發檢測,這是一些人的 “噩夢”。
在此有人吐槽到:“明明給我拋個錯就好了,憑什麼要讓我的 Go 進程直接崩潰掉,分分鐘給我背個 P0”。
場景枚舉
這裏我們假設一下,如果併發讀寫 map 是以下兩種場景:
-
產生 panic:程序 panic -> 默認走進 recover -> 沒有對併發 map 進行處理 -> map 存在髒數據 -> 程序使用髒數據 -> 產生 ** 未知 ((影響。
-
產生 crash:程序 crash -> 直接崩潰 -> 保全數據(數據正常)-> 產生 ** 明確 ((風險。
你會選擇哪一種方案呢?Go 官方在兩者的風險衡量中選擇了第二種。
無論是編程,還是人生。如何在隨機性中掌握確定性的部分,也是一門極大的哲學了。
let it crash
Go 官方團隊選擇的方式是業內經典的 “let it crash” 行爲,很多編程語言中,都會將其奉行爲設計哲學。
let it crash 是指工程師不必過分擔心未知的錯誤,而去進行面面俱到的防禦性編碼。
這塊理念最經典的就是 erlang 了。
總結
在今天這篇文章中,我們介紹了 Go 語言爲什麼不支持原生支持 map 併發,核心原因是大部分場景都不需要,從性能考慮上做的考慮。
直接讓併發讀寫 map 的原因,是從 “let it crash” 去考慮。這塊如果你想在自己的工程中避免這個情況,可以在 linter 等工具鏈加入競態檢測(-race),也可以避免這類風險。
關注煎魚,獲取業內第一手消息和知識 👇
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/70ttSbuQ3RpgKkaaIj3D1g