1. 「Go實(shí)戰(zhàn)系列」Go 語言中的一些非常規(guī)優(yōu)化

        共 2195字,需瀏覽 5分鐘

         ·

        2021-08-29 06:28

        這次去 Gopher China 和不少老朋友見了個(gè)面,還有不少在微信上認(rèn)識(shí)已久,一直沒見過面的網(wǎng)友。同時(shí)也和各個(gè)公司的一線開發(fā)們聊了聊,互相交流了彼此使用 Go 時(shí)的一些心得和痛點(diǎn)。

        綜合近期了解的一些相關(guān)分享,我把到目前為止見到的,不那么常見的,各方對(duì) Go 的優(yōu)化和 hack 集中在這篇文章里。因?yàn)榭紤]到一些公司情況比較特殊,所以本文中列出的點(diǎn)就不標(biāo)記是哪個(gè)公司做的了。未來他們覺得時(shí)機(jī)成熟應(yīng)該也會(huì)自己出來做一些分享。

        01

        網(wǎng)絡(luò)方面


        當(dāng)前 Go 的網(wǎng)絡(luò)抽象在效率上有些低,每一個(gè)連接至少要有一個(gè) goroutine 來維護(hù),有些協(xié)議實(shí)現(xiàn)可能有兩個(gè)。因此 goroutine 總數(shù) = 連接數(shù) * 1 or 連接數(shù) * 2。當(dāng)連接數(shù)超過 10w 時(shí),goroutine 棧本身帶來的內(nèi)存消耗就有幾個(gè) GB。

        大量的 goroutine 也會(huì)給調(diào)度和 GC 均帶來很大壓力。Go 底層的網(wǎng)絡(luò)庫(kù)和加密庫(kù)效率也不是很高,所以在同類應(yīng)用上和 C++ 等語言有較大性能差距(內(nèi)存、吞吐量)。

        社區(qū)有不少使用裸調(diào) Epoll 實(shí)現(xiàn)優(yōu)化的庫(kù),就不給他們打廣告了。由于用戶的 syscall.EpollWait 是運(yùn)行在一個(gè)沒有任何優(yōu)先級(jí)的 goroutine 中,當(dāng) CPU idle 較低時(shí),系統(tǒng)整體的延遲不可控,比標(biāo)準(zhǔn)庫(kù)的延遲還要高很多。之前個(gè)人做過相關(guān)的測(cè)試,核心數(shù)的增加也會(huì)使系統(tǒng)相應(yīng)的延遲大幅上升。

        接下來不同的公司的優(yōu)化思路就走向了兩個(gè)方向:

        1. 修改 runtime,在 runtime 增加用戶 Epoll 函數(shù)的回調(diào)。類似 runtime 自己實(shí)現(xiàn)的 netpoll 那樣。這種方式會(huì)導(dǎo)致 Go 本身難以升級(jí),必須跟著有 hack 的版本走。當(dāng)遇到 Go 的 bug 時(shí)會(huì)比較尷尬。
        2. 把 c 實(shí)現(xiàn)的網(wǎng)絡(luò)庫(kù)當(dāng)作基礎(chǔ)組件,把 Go 實(shí)現(xiàn)的業(yè)務(wù)邏輯作為業(yè)務(wù)嫁接在 c 庫(kù)之上。

        Go 語言的強(qiáng)項(xiàng)就是在網(wǎng)絡(luò)編程上,現(xiàn)在卻逼得大家為了優(yōu)化都需要去做對(duì) runtime 的 hack,甚至嫁接其它語言,這不能不說有點(diǎn)悲哀。還是希望未來官方能夠有更好的底層基礎(chǔ)工具來支持這種超高連接數(shù)的場(chǎng)景。

        02

        cgo

        因?yàn)?c 歷史悠久,所以對(duì) cgo 的使用是難以避免的,個(gè)人見到比較多的,比如做國(guó)際化需求必須要用到的 icu 庫(kù),只能用 cgo 來調(diào)。或者做 cv 的 opencv,也只能用 cgo。或者國(guó)密場(chǎng)景,也只能用 cgo。

        但從 go 調(diào)用到 c,有一次棧切換,成本有些高,所以有公司實(shí)現(xiàn)了從 go 切換到 c 不需要切換棧的神奇調(diào)用方式,同時(shí)在棧上打標(biāo)記,讓 GC 只掃描 Go 的棧而不掃描 c 的棧。

        03

        go-plugin

        官方提供的 go plugin 還是比較難用的,比如要求編譯版本必須統(tǒng)一;加載后無法卸載等。

        現(xiàn)在有公司基于 .got 表,實(shí)現(xiàn)了比官方的 plugin 更靈活的熱加載,熱卸載的動(dòng)態(tài)庫(kù)。

        (這條我不太懂,所以只是聽說,有問題歡迎指出

        04

        匯編優(yōu)化

        Go 語言的編譯后端都是 Go 自己實(shí)現(xiàn)的,沒有借助以往的平臺(tái),如 LLVM。

        有人將 C 語言編寫的等價(jià)代碼用較高的優(yōu)化級(jí)別,如 clang -o3,編譯為高度優(yōu)化的匯編,再翻譯為 plan9 匯編,整合成函數(shù)供 Go 應(yīng)用調(diào)用,這樣相當(dāng)于在 Go 里享受了 llvm 平臺(tái)的后端優(yōu)化成果。

        05

        runtime 修改

        除了前面提到的網(wǎng)絡(luò)編程時(shí),epollwait 需要高優(yōu)先級(jí)的 goroutine,在其它一些涉及到任務(wù)分發(fā),任務(wù)處理的應(yīng)用程序中也需要類似的高優(yōu)先級(jí) goroutine。

        所以有公司直接在 runtime 提供了接口,讓用戶可以通過接口來創(chuàng)建特殊優(yōu)先級(jí)的 goroutine。

        除了暴露接口外,對(duì) runtime 的實(shí)現(xiàn)代碼也是要做不少修改的。

        06

        通過 SSA 進(jìn)行的靜態(tài)檢查

        我們知道,當(dāng)前社區(qū)的 golangci-lint 大多是用 Go 內(nèi)置的編譯前端來完成的,在編譯后的 ast 上做一些邏輯,來提示用戶代碼中可能存在的問題。

        在一些較底層的編程場(chǎng)景,希望能夠消滅所有的堆分配,所以他們通過檢查生成的 SSA 中是否有 newobject 的調(diào)用來輔助進(jìn)行代碼的優(yōu)化。

        07

        垃圾回收

        Go 語言的垃圾回收沒有分代,分代會(huì)涉及到不同代際之間的對(duì)象移動(dòng),從 Go 官方歷史上的分享來看,Go 的開發(fā)者們對(duì) non-moving 比較執(zhí)著。因?yàn)槿绻焉蠈?duì)象會(huì) move 的話,需要在讀對(duì)象時(shí)開啟 read barrier,幾乎所有場(chǎng)景都是讀多寫少的場(chǎng)景,這樣會(huì)極大影響程序性能,所以官方現(xiàn)在在分代的研發(fā)上處于停滯狀態(tài)。

        國(guó)內(nèi)某公司在之前官方分代 GC CL 的基礎(chǔ)上實(shí)現(xiàn)了分代垃圾回收,不過因?yàn)榭床坏酱a,不太清楚他們最終在生產(chǎn)環(huán)境是否能夠達(dá)到較好的性能改善。

        08

        總結(jié)

        未來如果發(fā)現(xiàn)更多值得一聊的優(yōu)化的話,也許會(huì)寫個(gè)續(xù)。

        本篇中的內(nèi)容都是簡(jiǎn)單的介紹,沒有太多細(xì)節(jié),如果感興趣的讀者比較多的話,我們后續(xù)把每一點(diǎn)都展開來講講~


        想要獲取實(shí)戰(zhàn)營(yíng)的相關(guān)信息,請(qǐng)掃碼進(jìn)群哦~


        如果群滿,可加小助手,就能拉你一起加入群聊啦




        瀏覽 44
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 91伦理在线观看 | 国产视频手机在线 | 大香蕉国产三级 | 99热| 成人资源在线观看 |