Others
關(guān)于Go悲柱,還有哪些重要的技術(shù)值得了解的民晒,下面詳細(xì)分享芙贫。
GC
GC一般是C/C++程序員對(duì)于Go最常見(jiàn),也是最先想到的一個(gè)質(zhì)疑傍药,GC這玩意兒能行嗎磺平?我們以前C/C++程序都是自己實(shí)現(xiàn)內(nèi)存池的,我們內(nèi)存分配算法非常牛逼的拐辽。
Go的GC優(yōu)化之路拣挪,可以詳細(xì)讀Getting to Go: The Journey of Go's Garbage Collector
。
2014年Go1.4俱诸,GC還是很弱的菠劝,是決定Go生死的大短板。
上圖是Twitter的線(xiàn)上服務(wù)監(jiān)控睁搭。Go1.4的STW(Stop the World) Pause time是300毫秒赶诊,而Go1.5優(yōu)化到了30毫秒笼平。
而Go1.6的GC暫停時(shí)間降低到了3毫秒左右。
Go1.8則降低到了0.5毫秒左右舔痪,也就是500微秒寓调。從Go1.4到Go1.8,優(yōu)化了600倍性能锄码。
如何看GC的STW時(shí)間呢夺英?可以引入net/http/pprof
這個(gè)庫(kù),然后通過(guò)curl來(lái)獲取數(shù)據(jù)滋捶,實(shí)例代碼如下:
package main
import (
"net/http"
_ "net/http/pprof"
)
func main() {
http.ListenAndServe("localhost:6060", nil)
}
啟動(dòng)程序后痛悯,執(zhí)行命令就可以拿到結(jié)果(由于上面的例子中沒(méi)有GC,下面的數(shù)據(jù)取的是另外程序的部分?jǐn)?shù)據(jù)):
$ curl 'http://localhost:6060/debug/pprof/allocs?debug=1' 2>/dev/null |grep PauseNs
# PauseNs = [205683 79032 202102 82216 104853 142320 90058 113638 152504
145965 72047 49690 158458 60499 99610 112754 122262 52252 49234 68420 159857
97940 226085 103644 135428 245291 141997 92470 79974 132817 74634 65653 73582
47399 51653 86107 48619 62583 68906 131868 111903 85482 44531 74585 50162
31445 107397 10903081771 92603 58585 96620 40416 29763 102248 32804 49394
83715 77099 108983 66133 47832 35379 143949 69235 27820 35677 99430 104303
132657 63542 39434 126418 63845 167969 116438 68904 77899 136506 119708 47501]
可以用python計(jì)算最大值是322微秒重窟,最小是26微秒载萌,平均值是81微秒。
Declaration Syntax
關(guān)于Go的聲明語(yǔ)法Go Declaration Syntax
亲族,和C語(yǔ)言有對(duì)比炒考,在The "Clockwise/Spiral Rule"
這個(gè)文章中也詳細(xì)描述了C的順時(shí)針語(yǔ)法規(guī)則。其中有個(gè)例子:
int (*signal(int, void (*fp)(int)))(int);
這個(gè)是個(gè)什么呢霎迫?翻譯成Go語(yǔ)言就能看得很清楚:
func signal(a int, b func(int)) func(int)int
signal是個(gè)函數(shù)斋枢,有兩個(gè)參數(shù),返回了一個(gè)函數(shù)指針知给。signal的第一個(gè)參數(shù)是int瓤帚,第二個(gè)參數(shù)是一個(gè)函數(shù)指針。
當(dāng)然實(shí)際上C語(yǔ)言如果借助typedef也是能獲得比較好的可讀性的:
typedef void (*PFP)(int);
typedef int (*PRET)(int);
PRET signal(int a, PFP b);
只是從語(yǔ)言的語(yǔ)法設(shè)計(jì)上來(lái)說(shuō)涩赢,還是Go的可讀性確實(shí)會(huì)好一些戈次。這些點(diǎn)點(diǎn)滴滴的小傲嬌,是否可以支撐我們夠浪程序員浪起來(lái)的資本呢筒扒?至少Rob Pike不是拍腦袋和大腿想出來(lái)的規(guī)則嘛怯邪,這種認(rèn)真和嚴(yán)謹(jǐn)是值得佩服和學(xué)習(xí)的。
Documents
新的語(yǔ)言文檔支持都很好花墩,不用買(mǎi)本書(shū)看悬秉,Go也是一樣,Go官網(wǎng)歷年比較重要的文章包括:
- 語(yǔ)法特性及思考:
Go Declaration Syntax
,The Laws of Reflection
,Constants
,Generics Discussion
,Another Go at Language Design
,Composition not inheritance
,Interfaces and other types
- 并發(fā)相關(guān)特性:
Share Memory By Communicating
,Go Concurrency Patterns: Timing out, moving on
,Concurrency is not parallelism
,Advanced Go Concurrency Patterns
,Go Concurrency Patterns: Pipelines and cancellation
,Go Concurrency Patterns: Context
,Mutex or Channel
- 錯(cuò)誤處理相關(guān):
Defer, Panic, and Recover
,Error handling and Go
,Errors are values
,Stack traces and the errors package
,Error Handling In Go
,The Error Model
- 性能和優(yōu)化:
Profiling Go Programs
,Introducing the Go Race Detector
,The cover story
,Introducing HTTP Tracing
,Data Race Detector
- 標(biāo)準(zhǔn)庫(kù)說(shuō)明:
Go maps in action
,Go Slices: usage and internals
,Arrays, slices (and strings): The mechanics of append
,Strings, bytes, runes and characters in Go
- 和C的結(jié)合:
C? Go? Cgo!
- 項(xiàng)目相關(guān):
Organizing Go code
,Package names
,Effective Go
,versioning
,Russ Cox: vgo
- 關(guān)于GC:
Go GC: Prioritizing low latency and simplicity
,Getting to Go: The Journey of Go Garbage Collector
,Proposal: Eliminate STW stack re-scanning
其中冰蘑,文章中有引用其他很好的文章和泌,我也列出來(lái)哈:
-
Go Declaration Syntax
,引用了一篇神作祠肥,介紹C的螺旋語(yǔ)法,寫(xiě)C的多,讀過(guò)這個(gè)的不多东羹,The "Clockwise/Spiral Rule"
-
Strings, bytes, runes and characters in Go
,引用了很好的一篇文章百姓,號(hào)稱(chēng)每個(gè)人都要懂的,關(guān)于字符集和Unicode的文章垒拢,Every Software Developer Must Know (No Excuses!)
- 為何錯(cuò)誤碼模型,比異常模型更有優(yōu)勢(shì)求类,參考Cleaner, more elegant, and wrong 以及Cleaner, more elegant, and harder to recognize。
- Go中的面向?qū)ο笤O(shè)計(jì)原則SOLID尸疆。
- Go的版本語(yǔ)義Semantic Versioning,如何在大型項(xiàng)目中規(guī)范版本寿弱,避免導(dǎo)致依賴(lài)地獄(Dependency Hell)問(wèn)題。
SRS
SRS是使用ST症革,單進(jìn)程單線(xiàn)程,性能是EDSM模型的nginx-rtmp的3到5倍噪矛,參考SRS: Performance,當(dāng)然不是ST本身性能是EDSM的三倍铺罢,而是說(shuō)ST并不會(huì)比EDSM性能低艇挨,主要還是要根據(jù)業(yè)務(wù)上的特征做優(yōu)化。
關(guān)于ST和EDSM韭赘,參考本文前面關(guān)于Concurrency對(duì)于協(xié)程的描述缩滨,ST它是C的一個(gè)協(xié)程庫(kù),EDSM是異步事件驅(qū)動(dòng)模型泉瞻。
SRS是單進(jìn)程單線(xiàn)程楷怒,可以擴(kuò)展為多進(jìn)程,可以在SRS中改代碼Fork子進(jìn)程瓦灶,或者使用一個(gè)TCP代理,比如TCP代理go-oryx: rtmplb抱完。
在2016年和2017年我用Go重寫(xiě)過(guò)SRS贼陶,驗(yàn)證過(guò)Go使用2CPU可以跑到C10K,參考go-oryx,v0.1.13 Supports 10k(2CPUs) for RTMP players
碉怔。由于僅僅是語(yǔ)言的差異而重寫(xiě)一個(gè)項(xiàng)目烘贴,沒(méi)有找到更好的方式或理由,覺(jué)得很不值得撮胧,所以還是放棄了Go語(yǔ)言版本桨踪,只維護(hù)C++版本的SRS。Go目前一般在API服務(wù)器用得比較多芹啥,能否在流媒體服務(wù)器中應(yīng)用锻离?答案是肯定的,我已經(jīng)實(shí)現(xiàn)過(guò)了墓怀。
后來(lái)在2017年汽纠,終于找到相對(duì)比較合理的方式來(lái)用Go寫(xiě)流媒體,就是只提供庫(kù)而不是二進(jìn)制的服務(wù)器傀履,參考go-oryx-lib虱朵。
目前Go可以作為SRS前面的代理,實(shí)現(xiàn)多核的優(yōu)勢(shì)钓账,參考go-oryx碴犬。
Links
由于簡(jiǎn)書(shū)限制了文章字?jǐn)?shù),只好分成不同章節(jié):
- Overview 為何Go有時(shí)候也叫Golang?為何要選擇Go作為服務(wù)器開(kāi)發(fā)的語(yǔ)言梆暮?是沖動(dòng)服协?還是騷動(dòng)?Go的重要里程碑和事件惕蹄,當(dāng)年吹的那些牛逼蚯涮,都實(shí)現(xiàn)了哪些遭顶?
- Could Not Recover 君可知棒旗,有什么panic是無(wú)法recover的?包括超過(guò)系統(tǒng)線(xiàn)程限制铣揉,以及map的競(jìng)爭(zhēng)寫(xiě)逛拱。當(dāng)然一般都能recover台猴,比如Slice越界、nil指針曹步、除零、寫(xiě)關(guān)閉的chan等尿孔。
- Errors 為什么Go2的草稿3個(gè)有2個(gè)是關(guān)于錯(cuò)誤處理的活合?好的錯(cuò)誤處理應(yīng)該怎么做竹捉?錯(cuò)誤和異常機(jī)制的差別是什么块差?錯(cuò)誤處理和日志如何配合?
- Logger 為什么標(biāo)準(zhǔn)庫(kù)的Logger是完全不夠用的状蜗?怎么做日志切割和輪轉(zhuǎn)鹉动?怎么在混成一坨的服務(wù)器日志中找到某個(gè)連接的日志泽示?甚至連接中的流的日志?怎么做到簡(jiǎn)潔又夠用捎泻?
- Interfaces 什么是面向?qū)ο蟮腟OLID原則笆豁?為何Go更符合SOLID赤赊?為何接口組合比繼承多態(tài)更具有正交性抛计?Go類(lèi)型系統(tǒng)如何做到looser, organic, decoupled, independent, and therefore scalable?一般軟件中如果出現(xiàn)數(shù)學(xué)录豺,要么真的牛逼要么裝逼。正交性這個(gè)數(shù)學(xué)概念在Go中頻繁出現(xiàn),是神仙還是妖怪弟断?為何接口設(shè)計(jì)要考慮正交性阀趴?
- Modules 如何避免依賴(lài)地獄(Dependency Hell)?小小的版本號(hào)為何會(huì)帶來(lái)大災(zāi)難棚菊?Go為什么推出了GOPATH叔汁、Vendor還要搞module和vgo据块?新建了16個(gè)倉(cāng)庫(kù)做測(cè)試,碰到了9個(gè)坑像屋,搞清楚了gopath和vendor如何遷移己莺,以及vgo with vendor如何使用(畢竟生產(chǎn)環(huán)境不能每次都去外網(wǎng)下載)戈轿。
- Concurrency & Control 服務(wù)器中的并發(fā)處理難在哪里凶杖?為什么說(shuō)Go并發(fā)處理優(yōu)勢(shì)占領(lǐng)了云計(jì)算開(kāi)發(fā)語(yǔ)言市場(chǎng)?什么是C10K腾么、C10M問(wèn)題解虱?如何管理goroutine的取消漆撞、超時(shí)和關(guān)聯(lián)取消?為何Go1.7專(zhuān)門(mén)將context放到了標(biāo)準(zhǔn)庫(kù)悍汛?context如何使用离咐,以及問(wèn)題在哪里?
- Engineering Go在工程化上的優(yōu)勢(shì)是什么昆著?為什么說(shuō)Go是一門(mén)面向工程的語(yǔ)言凑懂?覆蓋率要到多少比較合適梧宫?什么叫代碼可測(cè)性?為什么良好的庫(kù)必須先寫(xiě)Example疤坝?
- Go2 Transition Go2會(huì)像Python3不兼容Python2那樣作嗎跑揉?C和C++的語(yǔ)言演進(jìn)可以有什么不同的收獲埠巨?Go2怎么思考語(yǔ)言升級(jí)的問(wèn)題辣垒?
- SRS & Others Go在流媒體服務(wù)器中的使用。Go的GC靠譜嗎脱衙?Twitter說(shuō)相當(dāng)?shù)目孔V捐韩,有圖有真相鹃锈。為何Go的聲明語(yǔ)法是那樣屎债?C的又是怎樣垢油?是拍的大腿滩愁,還是拍的腦袋惊楼?