大道至簡—GO語言最佳實踐

導(dǎo)讀:2007年,受夠了C++煎熬的Google首席軟件工程師Rob Pike糾集Robert Griesemer和Ken Thompson兩位牛人,決定創(chuàng)造一種新語言來取代C++, 這就是Golang涎劈。出現(xiàn)在21世紀(jì)的GO語言,雖然不能如愿對C++取而代之,但是其近C的執(zhí)行性能和近解析型語言的開發(fā)效率以及近乎于完美的編譯速度味咳,已經(jīng)風(fēng)靡全球闷叉。特別是在云項目中擦俐,大部分都使用了Golang來開發(fā),不得不說握侧,Golang早已深入人心蚯瞧。而對于一個沒有歷史負(fù)擔(dān)的新項目,Golang或許就是個不二的選擇品擎。

被稱為GO語言之父的Rob Pike說埋合,你是否同意GO語言,取決于你是認(rèn)可少就是多萄传,還是少就是少(Less is more or lessis less)甚颂。Rob Pike以一種非常樸素的方式,概括了GO語言的整個設(shè)計哲學(xué)--將簡單秀菱、實用體現(xiàn)得淋漓盡致振诬。

很多人將GO語言稱為21世紀(jì)的C語言,因為GO不僅擁有C的簡潔和性能衍菱,而且還很好的提供了21世紀(jì)互聯(lián)網(wǎng)環(huán)境下服務(wù)端開發(fā)的各種實用特性赶么,讓開發(fā)者在語言級別就可以方便的得到自己想要的東西。

本文大綱:

  • GO語言的發(fā)展與現(xiàn)狀

  • 發(fā)展歷史

  • 開發(fā)團(tuán)隊

  • 業(yè)務(wù)案例

  • GO語言關(guān)鍵特性

  • 并發(fā)與協(xié)程

  • 基于消息傳遞的通信方式

  • 豐富實用的內(nèi)置數(shù)據(jù)類型

  • 函數(shù)多返回值

  • Defer延遲處理機(jī)制

  • 反射(reflect)

  • 高性能HTTP Server

  • 工程管理

  • 編程規(guī)范

  • API快速開發(fā)框架實踐

  • 我們?yōu)槭裁催x擇GO語言

  • API框架的實現(xiàn)

  • 公共組件能力

  • 通用列表組件

  • 通用表單組件

  • 協(xié)程池

  • 數(shù)據(jù)校驗

  • 小結(jié)

  • 性能評測

  • 開發(fā)過程中需要注意的點

GO語言的發(fā)展與現(xiàn)狀

發(fā)展歷史

2007年9月脊串,Rob Pike在Google分布式編譯平臺上進(jìn)行C++編譯辫呻,在漫長的等待過程中,他和Robert Griesemer探討了程序設(shè)計語言的一些關(guān)鍵性問題洪规,他們認(rèn)為印屁,簡化編程語言相比于在臃腫的語言上不斷增加新特性,會是更大的進(jìn)步斩例。隨后他們在編譯結(jié)束之前說服了身邊的Ken Thompson雄人,覺得有必要為此做一些事情。幾天后念赶,他們發(fā)起了一個叫Golang的項目础钠,將它作為自由時間的實驗項目。

2008年5月 Google發(fā)現(xiàn)了GO語言的巨大潛力叉谜,得到了Google的全力支持旗吁,這些人開始全職投入GO語言的設(shè)計和開發(fā)。

2009年11月 GO語言第一個版本發(fā)布停局。2012年3月 第一個正式版本Go1.0發(fā)布很钓。

2015年8月 go1.5發(fā)布香府,這個版本被認(rèn)為是歷史性的。完全移除C語言部分码倦,使用GO編譯GO企孩,少量代碼使用匯編實現(xiàn)。另外袁稽,他們請來了內(nèi)存管理方面的權(quán)威專家Rick Hudson勿璃,對GC進(jìn)行了重新設(shè)計,支持并發(fā)GC推汽,解決了一直以來廣為詬病的GC時延(STW)問題补疑。并且在此后的版本中,又對GC做了更進(jìn)一步的優(yōu)化歹撒。到go1.8時莲组,相同業(yè)務(wù)場景下的GC時延已經(jīng)可以從go1.1的數(shù)秒,控制在1ms以內(nèi)栈妆。GC問題的解決胁编,可以說GO語言在服務(wù)端開發(fā)方面,幾乎抹平了所有的弱點鳞尔。

在GO語言的版本迭代過程中嬉橙,語言特性基本上沒有太大的變化,基本上維持在GO1.1的基準(zhǔn)上寥假,并且官方承諾市框,新版本對老版本下開發(fā)的代碼完全兼容。事實上糕韧,GO開發(fā)團(tuán)隊在新增語言特性上顯得非常謹(jǐn)慎枫振,而在穩(wěn)定性、編譯速度萤彩、執(zhí)行效率以及GC性能等方面進(jìn)行了持續(xù)不斷的優(yōu)化粪滤。

開發(fā)團(tuán)隊

GO語言的開發(fā)陣營可以說是空前強(qiáng)大,主要成員中不乏計算機(jī)軟件界的歷史性人物雀扶,對計算機(jī)軟件的發(fā)展影響深遠(yuǎn)杖小。Ken Thompson,來自貝爾實驗室,設(shè)計了B語言,創(chuàng)立了Unix操作系統(tǒng)(最初使用B語言實現(xiàn))踪少,隨后在Unix開發(fā)過程中,又和Dennis Ritchie一同設(shè)計了C語言江醇,繼而使用C語言重構(gòu)了Unix操作系統(tǒng)。Dennis Ritchie和Ken Thompson被稱為Unix和C語言之父,并在1983年共同被授以圖靈獎,以表彰他們對計算機(jī)軟件發(fā)展所作的杰出貢獻(xiàn)笆环。Rob Pike攒至,同樣來自貝爾實驗室,Unix小組重要成員躁劣,發(fā)明了Limbo語言嗓袱,并且和Ken Thompson共同設(shè)計了UTF-8編碼,《Unix編程環(huán)境》习绢、《編程實踐》作者之一。

可以說蝙昙,GO語言背靠Google這棵大樹闪萄,又不乏牛人坐鎮(zhèn),是名副其實的“牛二代”奇颠。

大名鼎鼎的Docker败去,完全用GO實現(xiàn),業(yè)界最為火爆的容器編排管理系統(tǒng)kubernetes烈拒,完全用GO實現(xiàn)圆裕,之后的Docker Swarm,完全用GO實現(xiàn)荆几。除此之外吓妆,還有各種有名的項目如etcd/consul/flannel等等,均使用GO實現(xiàn)吨铸。有人說行拢,GO語言之所以出名,是趕上了云時代诞吱,但為什么不能換種說法舟奠,也是GO語言促使了云的發(fā)展?

除了云項目外房维,還有像今日頭條沼瘫、UBER這樣的公司,他們也使用GO語言對自己的業(yè)務(wù)進(jìn)行了徹底的重構(gòu)咙俩。

GO語言關(guān)鍵特性

GO語言之所以厲害耿戚,是因為它在服務(wù)端的開發(fā)中,總能抓住程序員的痛點暴浦,以最直接溅话、簡單、高效歌焦、穩(wěn)定的方式來解決問題飞几。這里我們并不會深入討論GO語言的具體語法,只會將語言中關(guān)鍵的独撇、對簡化編程具有重要意義的方面介紹給大家屑墨,跟隨大師們的腳步躁锁,體驗GO的設(shè)計哲學(xué)。

GO語言的關(guān)鍵特性主要包括以下幾方面:

  • 并發(fā)與協(xié)程

  • 基于消息傳遞的通信方式

  • 豐富實用的內(nèi)置數(shù)據(jù)類型

  • 函數(shù)多返回值

  • defer機(jī)制

  • 反射(reflect)

  • 高性能HTTP Server

  • 工程管理

  • 編程規(guī)范

在當(dāng)今這個多核時代卵史,并發(fā)編程的意義不言而喻战转。當(dāng)然,很多語言都支持多線程以躯、多進(jìn)程編程槐秧,但遺憾的是,實現(xiàn)和控制起來并不是那么令人感覺輕松和愉悅忧设。Golang不同的是刁标,語言級別支持協(xié)程(goroutine)并發(fā)(協(xié)程又稱微線程,比線程更輕量址晕、開銷更小膀懈,性能更高),操作起來非常簡單谨垃,語言級別提供關(guān)鍵字(go)用于啟動協(xié)程启搂,并且在同一臺機(jī)器上可以啟動成千上萬個協(xié)程。

對比JAVA的多線程和GO的協(xié)程實現(xiàn)刘陶,明顯更直接胳赌、簡單。這就是GO的魅力所在匙隔,以簡單匈织、高效的方式解決問題,關(guān)鍵字go牡直,或許就是GO語言最重要的標(biāo)志缀匕。

基于消息傳遞的通信方式

在異步的并發(fā)編程過程中,只能方便碰逸、快速的啟動協(xié)程還不夠乡小。協(xié)程之間的消息通信,也是非常重要的一環(huán)饵史,否則满钟,各個協(xié)程就會成為脫韁的野馬而無法控制。在GO語言中胳喷,使用基于消息傳遞的通信方式(而不是大多數(shù)語言所使用的基于共享內(nèi)存的通信方式)進(jìn)行協(xié)程間通信湃番,并且將消息管道(channel)作為基本的數(shù)據(jù)類型,使用類型關(guān)鍵字(chan)進(jìn)行定義吭露,并發(fā)操作時線程安全吠撮。這點在語言的實現(xiàn)上,也具有革命性讲竿∧嗬迹可見弄屡,GO語言本身并非簡單得沒有底線,恰恰他們會將最實用鞋诗、最有利于解決問題的能力膀捷,以最簡單、直接的形式提供給用戶削彬。

Channel并不僅僅只是用于簡單的消息通信全庸,還可以引申出很多非常實用,而實現(xiàn)起來又非常方便的功能融痛。比如糕篇,實現(xiàn)TCP連接池、限流等等酌心,而這些在其它語言中實現(xiàn)起來并不輕松,但GO語言可以輕易做到挑豌。

GO語言作為編譯型語言安券,在數(shù)據(jù)類型上也支持得非常全面,除了傳統(tǒng)的整型氓英、浮點型侯勉、字符型、數(shù)組铝阐、結(jié)構(gòu)等類型外址貌。從實用性上考慮,也對字符串類型徘键、切片類型(可變長數(shù)組)练对、字典類型、復(fù)數(shù)類型吹害、錯誤類型螟凭、管道類型、甚至任意類型(Interface{})進(jìn)行了原生支持它呀,并且用起來非常方便螺男。比如字符串、切片類型纵穿,操作簡便性幾乎和python類似下隧。

另外,將錯誤類型(error)作為基本的數(shù)據(jù)類型谓媒,并且在語言級別不再支持try…catch的用法淆院,這應(yīng)該算是一個非常大膽的革命性創(chuàng)舉,也難怪很多人吐槽GO語言不倫不類句惯。但是跳出傳統(tǒng)的觀念迫筑,GO的開發(fā)者認(rèn)為在編程過程中宪赶,要保證程序的健壯性和穩(wěn)定性,對異常的精確化處理是非常重要的脯燃,只有在每一個邏輯處理完成后搂妻,明確的告知上層調(diào)用,是否有異常辕棚,并由上層調(diào)用明確欲主、及時的對異常進(jìn)行處理,這樣才可以高程度的保證程序的健壯性和穩(wěn)定性逝嚎。雖然這樣做會在編程過程中出現(xiàn)大量的對error結(jié)果的判斷扁瓢,但是這無疑也增強(qiáng)了開發(fā)者對異常處理的警惕度。而實踐證明补君,只要嚴(yán)格按GO推薦的風(fēng)格編碼引几,想寫出不健壯的代碼,都很難挽铁。當(dāng)然伟桅,前提是你不排斥它,認(rèn)可它叽掘。

在語言中支持函數(shù)多返回值楣铁,并不是什么新鮮事,Python就是其中之一更扁。允許函數(shù)返回多個值盖腕,在某些場景下,可以有效的簡化編程浓镜。GO語言推薦的編程風(fēng)格溃列,是函數(shù)返回的最后一個參數(shù)為error類型(只要邏輯體中可能出現(xiàn)異常),這樣膛薛,在語言級別支持多返回值哭廉,就很有必要了。

Defer延遲處理機(jī)制

在GO語言中相叁,提供關(guān)鍵字defer遵绰,可以通過該關(guān)鍵字指定需要延遲執(zhí)行的邏輯體,即在函數(shù)體return前或出現(xiàn)panic時執(zhí)行增淹。這種機(jī)制非常適合善后邏輯處理椿访,比如可以盡早避免可能出現(xiàn)的資源泄漏問題。

可以說虑润,defer是繼goroutine和channel之后的另一個非常重要成玫、實用的語言特性,對defer的引入,在很大程度上可以簡化編程哭当,并且在語言描述上顯得更為自然猪腕,極大的增強(qiáng)了代碼的可讀性。

Golang作為強(qiáng)類型的編譯型語言钦勘,靈活性上自然不如解析型語言陋葡。比如像PHP,弱類型彻采,并且可以直接對一個字符串變量的內(nèi)容進(jìn)行new操作腐缤,而在編譯型語言中,這顯然不太可能肛响。但是岭粤,Golang提供了Any類型(interface{})和強(qiáng)大的類型反射(reflect)能力,二者相結(jié)合特笋,開發(fā)的靈活性上已經(jīng)很接近解析型語言剃浇。在邏輯的動態(tài)調(diào)用方面,實現(xiàn)起來仍然非常簡單猎物。既然如此虎囚,那么像PHP這種解析型語言相比于GO,優(yōu)勢在那里呢霸奕?就我個人而言,寫了近10年的PHP吉拳,實現(xiàn)過開發(fā)框架质帅、基礎(chǔ)類庫以及各種公共組件,雖然執(zhí)行性能不足留攒,但是開發(fā)效率有余煤惩;而當(dāng)遇上Golang,這些優(yōu)勢似乎不那么明顯了炼邀。

作為出現(xiàn)在互聯(lián)網(wǎng)時代的服務(wù)端語言魄揉,面向用戶服務(wù)的能力必不可少。GO在語言級別自帶HTTP/TCP/UDP高性能服務(wù)器拭宁,基于協(xié)程并發(fā)洛退,為業(yè)務(wù)開發(fā)提供最直接有效的能力支持。要在GO語言中實現(xiàn)一個高性能的HTTP Server杰标,只需要幾行代碼即可完成兵怯,非常簡單。

在GO語言中腔剂,有一套標(biāo)準(zhǔn)的工程管理規(guī)范媒区,只要按照這個規(guī)范進(jìn)行項目開發(fā),之后的事情(比如包管理、編譯等等)都將變得非常的簡單袜漩。

在GO項目下绪爸,存在兩個關(guān)鍵目錄,一個是src目錄宙攻,用于存放所有的.go源碼文件奠货;一個是bin目錄,用于存在編譯后的二進(jìn)制文件粘优。在src目錄下仇味,除了main主包所在的目錄外,其它所有的目錄名稱與直接目錄下所對應(yīng)的包名保持對應(yīng)雹顺,否則編譯無法通過丹墨。這樣,GO編譯器就可以從main包所在的目錄開始嬉愧,完全使用目錄結(jié)構(gòu)和包名來推導(dǎo)工程結(jié)構(gòu)以及構(gòu)建順序贩挣,避免像C++一樣,引入一個額外的Makefile文件没酣。

在GO的編譯過程中王财,我們唯一要做的就是將GO項目路徑賦值給一個叫GOPATH的環(huán)境變量,讓編譯器知道將要編譯的GO項目所在的位置裕便。然后進(jìn)入bin目錄下绒净,執(zhí)行g(shù)o build {主包所在的目錄名},即可秒級完成工程編譯偿衰。編譯后的二進(jìn)制文件挂疆,可以推到同類OS上直接運(yùn)行,沒有任何環(huán)境依賴下翎。

GO語言的編程規(guī)范強(qiáng)制集成在語言中缤言,比如明確規(guī)定花括號擺放位置,強(qiáng)制要求一行一句视事,不允許導(dǎo)入沒有使用的包胆萧,不允許定義沒有使用的變量,提供gofmt工具強(qiáng)制格式化代碼等等俐东。奇怪的是跌穗,這些也引起了很多程序員的不滿,有人發(fā)表GO語言的XX條罪狀虏辫,里面就不乏對編程規(guī)范的指責(zé)瞻离。要知道,從工程管理的角度乒裆,任何一個開發(fā)團(tuán)隊都會對特定語言制定特定的編程規(guī)范套利,特別像Google這樣的公司推励,更是如此。GO的設(shè)計者們認(rèn)為肉迫,與其將規(guī)范寫在文檔里验辞,還不如強(qiáng)制集成在語言里,這樣更直接喊衫,更有利用團(tuán)隊協(xié)作和工程管理跌造。

API快速開發(fā)框架實踐

編程語言是一個工具,它會告訴我們能做什么族购,而怎么做會更好壳贪,同樣值得去探討。這部分會介紹用GO語言實現(xiàn)的一個開發(fā)框架寝杖,以及幾個公共組件违施。當(dāng)然,框架和公共組件瑟幕,其它語言也完全可以實現(xiàn)磕蒲,而這里所關(guān)注的是成本問題。除此之外只盹,拋開GO語言本身不說辣往,我們也希望可以讓大家從介紹的幾個組件中,得到一些解決問題的思路殖卑,那就是通過某種方式站削,去解決一個面上的問題,而非一味的寫代碼孵稽,最終卻只是解決點上的問題许起。如果你認(rèn)可這種方式,相信下面的內(nèi)容也許會影響你之后的項目開發(fā)方式肛冶,從根本上提高開發(fā)效率街氢。

我們?yōu)槭裁催x擇GO語言

選擇GO語言扯键,主要是基于兩方面的考慮

1. 執(zhí)行性能

縮短API的響應(yīng)時長睦袖,解決批量請求訪問超時的問題。在Uwork的業(yè)務(wù)場景下荣刑,一次API批量請求馅笙,往往會涉及對另外接口服務(wù)的多次調(diào)用,而在之前的PHP實現(xiàn)模式下厉亏,要做到并行調(diào)用是非常困難的董习,串行處理卻不能從根本上提高處理性能。而GO語言不一樣爱只,通過協(xié)程可以方便的實現(xiàn)API的并行處理皿淋,達(dá)到處理效率的最大化。

依賴Golang的高性能HTTP Server,提升系統(tǒng)吞吐能力窝趣,由PHP的數(shù)百級別提升到數(shù)千里甚至過萬級別疯暑。

2. 開發(fā)效率

GO語言使用起來簡單、代碼描述效率高哑舒、編碼規(guī)范統(tǒng)一妇拯、上手快。

通過少量的代碼洗鸵,即可實現(xiàn)框架的標(biāo)準(zhǔn)化越锈,并以統(tǒng)一的規(guī)范快速構(gòu)建API業(yè)務(wù)邏輯。

能快速的構(gòu)建各種通用組件和公共類庫膘滨,進(jìn)一步提升開發(fā)效率甘凭,實現(xiàn)特定場景下的功能量產(chǎn)。

很多人在學(xué)習(xí)一門新語言或開啟一個新項目時吏祸,都會習(xí)慣性的是網(wǎng)上找一個認(rèn)為合適的開源框架來開始自己的項目開發(fā)之旅对蒲。這樣并沒有什么不好,但是個人覺得贡翘,了解它內(nèi)部的實現(xiàn)對我們會更有幫助蹈矮。或許大家已經(jīng)注意到了鸣驱,所說的MVC框架泛鸟,其本質(zhì)上就是對請求路徑進(jìn)行解析,然后根據(jù)請求路徑段踊东,路由到相應(yīng)的控制器(C)上北滥,再由控制器進(jìn)一步調(diào)用數(shù)據(jù)邏輯(M),拿到數(shù)據(jù)后闸翅,渲染視圖(V)再芋,返回用戶。在整個過程中坚冀,核心點在于邏輯的動態(tài)調(diào)用济赎。

不過,對API框架的實現(xiàn)相對于WEB頁面框架的實現(xiàn)记某,會更簡單司训,因為它并不涉及視圖的渲染,只需要將數(shù)據(jù)結(jié)果以協(xié)議的方式返回給用戶即可液南。

使用GO語言實現(xiàn)一套完整的MVC開發(fā)框架壳猜,是非常容易的,集成HTTP Server的同時滑凉,整個框架的核心代碼不會超過300行统扳,從這里可以實際感受到GO的語言描述效率之高(如果有興趣喘帚,可以參考Uwork開源項目seine)。

也有人說咒钟,在GO語言中啥辨,就沒有框架可言,言外之意是說盯腌,引入一個重型的開源框架溉知,必要性并不大,相反還可能把簡單的東西復(fù)雜化腕够。

在實際項目開發(fā)過程中级乍,只有高效的開發(fā)語言還不夠,要想進(jìn)一步將開發(fā)效率擴(kuò)大化帚湘,不斷的沉淀公共基礎(chǔ)庫是必不可少的玫荣,以便將通用的基礎(chǔ)邏輯進(jìn)一步抽象和復(fù)用。

除此之外大诸,通用組件能力是實現(xiàn)功能量產(chǎn)的根本捅厂,對開發(fā)效率會是質(zhì)的提升。組件化的開發(fā)模式會幫忙我們將問題的解決能力從一個點上提升到一個面上资柔。以下會重點介紹幾個通用組件的實現(xiàn)焙贷,有了它們的存在,才能真正的解放程序員的生產(chǎn)力贿堰。而這些強(qiáng)有力的公共組件在Golang中實現(xiàn)起來并不復(fù)雜辙芍。同時,結(jié)合Golang的并發(fā)處理能力羹与,相比于PHP的版本實現(xiàn)故硅,執(zhí)行效率也會有質(zhì)的提升。這是組件能力和語言效率的完美結(jié)合纵搁。

通用列表組件用于所有可能的二維數(shù)據(jù)源(如MySQL/MongoDB/ES等等)的數(shù)據(jù)查詢場景吃衅,從一個面上解決了數(shù)據(jù)查詢問題。在Uwork項目開發(fā)中腾誉,被大量使用徘层,實現(xiàn)數(shù)據(jù)查詢接口和頁面查詢列表的量產(chǎn)開發(fā)。它以一個JSON配置文件為中心妄辩,來實現(xiàn)對通用數(shù)據(jù)源的查詢惑灵,并將查詢結(jié)果以API或頁面的形式自動返回給用戶山上。整個過程中幾乎沒有代碼開發(fā)眼耀,而唯一要做的只是以一種統(tǒng)一的規(guī)范編寫配置文件(而不是代碼),真正實現(xiàn)了對數(shù)據(jù)查詢需求的功能量產(chǎn)佩憾。

以上是通用列表組件的構(gòu)建過程哮伟,要實現(xiàn)這樣一個功能強(qiáng)大的通用組件干花,是不是會給人一種可望而不可及的感覺?其實并非如此楞黄,只要理清了它的整個過程池凄,將構(gòu)建思路融入Golang中,并不是一件復(fù)雜的事情鬼廓。在我們的項目中肿仑,整個組件的實現(xiàn),只用了不到700行Go代碼碎税,就解決了一系列的數(shù)據(jù)查詢問題尤慰。另外,通過Golang的并發(fā)特性雷蹂,實現(xiàn)字段處理器的并行執(zhí)行伟端,進(jìn)一步的提高了組件的執(zhí)行效率》嘶停可以說责蝠,通用列表和Golang的融合,是性能和效率的完美結(jié)合萎庭。

通用表單組件主要用于對數(shù)據(jù)庫的增霜医、刪、改場景驳规。該組件在Uwork的項目開發(fā)中支子,也有廣泛的應(yīng)用,與通用列表類似达舒,以一個JSON配置文件為中心值朋,來完成對數(shù)據(jù)表數(shù)據(jù)的增、刪巩搏、改操作昨登。特別是近期完成的部件級SDB管理平臺,通過通用表單實現(xiàn)了對整個系統(tǒng)的數(shù)據(jù)維護(hù)贯底,通過高度抽象化丰辣,做到了業(yè)務(wù)的無代碼化生產(chǎn)。

以上是通用表單的完整構(gòu)建過程禽捆,而對于這個一個組件的實現(xiàn)笙什,我們用了不到1000行的GO代碼,就解決了對數(shù)據(jù)表數(shù)據(jù)維護(hù)整個面上的問題胚想。

GO語言本身支持協(xié)程并發(fā)琐凭,協(xié)程非常輕量,可以快速啟動成千上萬個協(xié)程工作單元浊服。如果對協(xié)程任務(wù)的數(shù)量控制不當(dāng)统屈,最后的結(jié)果很可能適得其反胚吁,從而對外部或本身的服務(wù)造成不必要的壓力。協(xié)程池可以在一定程度上控制執(zhí)行單元的數(shù)量愁憔,保證執(zhí)行的安全性腕扶。而在Golang中要實現(xiàn)這樣一個協(xié)程池,是非常簡單的吨掌,只需要對channel和goroutine稍加封裝半抱,就可以完成,整個構(gòu)建過程不到80行代碼膜宋。

在API開發(fā)過程中代虾,數(shù)據(jù)校驗永遠(yuǎn)是必不可或缺的一個環(huán)節(jié)。如果只是簡單的數(shù)據(jù)校驗激蹲,幾行代碼也許就完成了棉磨,可是當(dāng)遇上復(fù)雜的數(shù)據(jù)校驗時,很可能幾百行的代碼量也未必能完成学辱,特別是遇到遞歸類型的數(shù)據(jù)校驗乘瓤,那簡直就是一個噩夢。

數(shù)據(jù)校驗組件策泣,可以通過一種數(shù)據(jù)模板的配置方式衙傀,使用特定的邏輯來完成通用校驗,開發(fā)者只需要配置好相應(yīng)的數(shù)據(jù)模板萨咕,進(jìn)行簡單的調(diào)用统抬,即可完成整個校驗過程。而對于這樣一個通用性的數(shù)據(jù)校驗組件危队,在GO語言中只用了不到700行的代碼量就完成了整個構(gòu)建聪建。

小結(jié)

222.png

在實際項目開發(fā)過程中,對開發(fā)效率提升最大的茫陆,無疑是符合系統(tǒng)業(yè)務(wù)場景的公共組件能力金麸,這點也正好應(yīng)證了Rob Pike那句話(Less is lessor Less is more),真正的高效率開發(fā)簿盅,是配置化的挥下,并不需要寫太多的代碼,甚至根本就不需要寫代碼桨醋,即可完成邏輯實現(xiàn)棚瘟,而這種方式對于后期的維護(hù)成本也是最優(yōu)的,因為做到了高度的統(tǒng)一喜最。

GO的語言描述效率毋庸置疑偎蘸,對上述所有公共組件的實現(xiàn),均未超過1000行代碼,就解決了某個面上的問題禀苦。

(以上的部分代碼已經(jīng)在Uwork開源項目seine中提供)

性能評測

壓力測試環(huán)境說明:

  • 服務(wù)運(yùn)行機(jī)器:單臺空閑B6,24核CPU遂鹊、64G內(nèi)存振乏。

  • PHP API環(huán)境:Nginx+PHP-FPM,CI框架秉扑。其中Nginx啟動10個子進(jìn)程慧邮,每個子進(jìn)程最大接收1024個連接,php-fpm使用static模式舟陆,啟動2000個常駐子進(jìn)程误澳。

  • Golang API環(huán)境:使用go1.8.6編譯,直接拉起Golang API Server進(jìn)程(HttpServer)秦躯,不考慮調(diào)優(yōu)忆谓。

  • 客戶發(fā)起請求測試程序:使用Golang編寫,協(xié)程并發(fā)踱承,運(yùn)行在獨立的另外一臺空閑B6上倡缠,24核CPU,64G內(nèi)存茎活,依次在1-2000個不同級別(并發(fā)數(shù)步長為50)的并發(fā)上分別請求20000次昙沦。

壓力測試結(jié)果對比

在Golang API框架中,當(dāng)并發(fā)數(shù)>50時载荔,處理QPS在6.5w/s附近波動盾饮。表現(xiàn)穩(wěn)定,壓力測試過程無報錯懒熙。

Nginx+php-fpm丘损,只在index.php中輸出exit('ok'),當(dāng)并發(fā)數(shù)>50時工扎,處理QPS在1w/s附近波動号俐。表現(xiàn)穩(wěn)定,壓力測試過程無報錯定庵。

Nginx+php-fpm+CI框架中吏饿,邏輯執(zhí)行到具體業(yè)務(wù)邏輯點,輸出exit('ok')蔬浙,當(dāng)并發(fā)數(shù)>50時猪落,處理QPS在750/s附近波動。并且表現(xiàn)不穩(wěn)定畴博,壓力測試過程中隨著并發(fā)數(shù)的增大笨忌,錯誤量隨之增加。

通過壓力測試可以發(fā)現(xiàn)俱病,Golang和PHP在執(zhí)行性能上官疲,并沒有什么可比性袱结;而使用Golang實現(xiàn)的HTTP API框架,空載時單機(jī)性能QPS達(dá)到6.5w/s途凫,還是非常令人滿意的垢夹。

開發(fā)過程中需要注意的點

以下是在實際開發(fā)過程中遇到的一些問題,僅供參考:

  1. 異常處理統(tǒng)一使用error维费,不要使用panic/recover來模擬throw…catch果元,最初我是這么做的,后來發(fā)現(xiàn)這完全是自以為是的做法犀盟。

  2. 原生的error過于簡單而晒,而在實際的API開發(fā)過程中,不同的異常情況需要附帶不同的返回碼阅畴,基于此倡怎,有必要對error再進(jìn)行一層封裝。

  3. 任何協(xié)程邏輯執(zhí)行體贱枣,邏輯最開始處必須要有defer recover()異痴┦ぃ恢復(fù)處理,否則goroutine內(nèi)出現(xiàn)的panic冯事,將導(dǎo)致整個進(jìn)程宕掉焦匈,需要避免部分邏輯BUG造成全局影響。

  4. 在Golang中昵仅,變量(chan類型除外)的操作是非線程安全的缓熟,也包括像int這樣的基本類型,因此并發(fā)操作全局變量時一定要考慮加鎖摔笤,特別是對map的并發(fā)操作够滑。

  5. 所有對map鍵值的獲取,都應(yīng)該判斷存在性吕世,最好是對同類操作進(jìn)行統(tǒng)一封裝彰触,避免出現(xiàn)不必要的運(yùn)行時異常。

  6. 定義slice數(shù)據(jù)類型時命辖,盡量預(yù)設(shè)長度况毅,避免內(nèi)部出現(xiàn)不必要的數(shù)據(jù)重組。

本文來自:CSDN博客
感謝作者:Tencent_TEG
查看原文:大道至簡—GO語言最佳實踐

添加小編微信:grey0805尔艇,加入知識學(xué)習(xí)小分隊~尔许!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市终娃,隨后出現(xiàn)的幾起案子味廊,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件余佛,死亡現(xiàn)場離奇詭異柠新,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)辉巡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門恨憎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事∶呵剑” “怎么了距误?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長茉贡。 經(jīng)常有香客問我塞栅,道長,這世上最難降的妖魔是什么腔丧? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任放椰,我火速辦了婚禮,結(jié)果婚禮上愉粤,老公的妹妹穿的比我還像新娘砾医。我一直安慰自己,他們只是感情好衣厘,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布如蚜。 她就那樣靜靜地躺著,像睡著了一般影暴。 火紅的嫁衣襯著肌膚如雪错邦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天型宙,我揣著相機(jī)與錄音撬呢,去河邊找鬼。 笑死妆兑,一個胖子當(dāng)著我的面吹牛魂拦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搁嗓,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼晨另,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谱姓?” 一聲冷哼從身側(cè)響起借尿,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后路翻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狈癞,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年茂契,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝶桶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡掉冶,死狀恐怖真竖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厌小,我是刑警寧澤恢共,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站璧亚,受9級特大地震影響讨韭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜癣蟋,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一透硝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧疯搅,春花似錦濒生、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至琐馆,卻和暖如春规阀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘦麸。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工谁撼, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人滋饲。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓厉碟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親屠缭。 傳聞我的和親對象是個殘疾皇子箍鼓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容