微職位Golang開發工程師學習分享韓曉東

18年5月份接觸了51CTO推出的微職位Go課程,對Golang十分喜愛。通過張長志老師的視頻講解,前後4個月的學習時間。也用Golang寫了些簡單的代碼和例子,其中包括業餘時間的,也有項目中的。今天寫點Golang相關的總結,僅供各位同學參考。

特性少,語法簡單。GO是崇尚極簡主義的,提倡少即是多。這點在它的Spec上尤其凸顯,一下午的時間絕對可以看完。GO的特性很少,很多GO的使用者都反饋,GO的關鍵字至少完全可以記在大腦裏。同時它的語法極爲簡單,而且語義清晰。

部署方便。GO是一個強類型靜態語言,可以把代碼編譯爲本地機器指令。它的RUNTIME是會在編譯時一起鏈接到執行文件中,這也就意味着我們不需要像JAVA那樣裝一個JVM。而且編譯出的執行文件本身不依賴於其他動態庫,完全可以做到輕鬆的發佈。當然,如果你用GO編寫了調用一些動態庫接口的代碼,那麼還是需要根據實際情況來部署這個動態庫的。這點在很多從python/java轉到go的朋友來說,非常喜歡。

有較完善的標準庫並且較爲健壯。GO自身帶的標準庫是比較全面的,從文件歸檔、壓縮、加密、數據庫到數據序列化,字符格式化、校驗和以及網絡庫、同步庫等應有盡有。基本上能夠滿足很多基本的需求了。更好的是,這些標準庫的質量都非常高,都很健壯。接口也較爲簡單,有清晰的文檔說明。同時隨着這兩年的發展,GO的第三方庫也多了起來,雖然可能沒有像python那麼多,但是較其發展時間來說,還是非常不錯的。

集成測框架。在之前用C++寫代碼時,寫單元測試不是個容易的工作。需要一些技巧和努力纔可以做起來。但是在GO中集成了單元測試框架,只要源碼文件以_test.go結尾,就可以直接通過go test執行單元測試。同時還提供了代碼測試覆蓋率工具,可以很容易實施自動化測試。除此之外,還集成了基準測試框架功能,可以很容易的測量自己寫的函數的運行效率。另外,還有性能剖析器,可以在運行時,測試時剖析程序的瓶頸點,進而可以進行優化。

健全的代碼風格與檢查工具。當初學GO的時候,很多文章和書都會提到go fmt這個命令,統一了代碼風格。我覺着這點實在是解決了風格之爭了。帶來的影響就是別人寫的代碼感覺也是自己寫的一樣。還有golint,可以按照go team的風格和要求來寫代碼。還有go vet可以用來檢查一些在GO中很隱蔽的坑。

簡單卻強大的包管理。GO的包管理可能在很多其他語言的包管理看來太弱了,但是在我看來,它解決了我需要的兩個問題,一個是循環依賴問題,GO是拒絕有循環依賴關係的包;二是包的初始化,每個包的文件都可以實現一個init函數,用來在導入時執行。這點在分工合作時非常有用。

容易編寫跨平臺代碼。如果你用純GO,不牽扯到CGO的話,你可以非常容易的做到跨平臺。只需要在文件後綴.go前,引入_linux,_windows,_x86,_x64等字符爲文件名前綴的結尾就可以做到只在對應的平臺中編譯。GO還有build constraints控制代碼在什麼條件下編譯。如果你用到了CGO,就牽扯到了C的跨平臺問題,所以稍微麻煩那麼一些,但是問題也不是太大。

垃圾回收。GC的存在極大的降低了併發代碼的編寫,而且還提供了程序的健壯性。做爲一個從C/C++做起,有過驅動開發經驗的程序員來說,GC這個東西是我一直沒有涉獵過的。對我來說GC就等於噩夢。但是當我開始試着接受GC時發現,GC真的是解決了程序員的生產力,極大的提高了效率。雖然目前來說GO已經1.4版本了,但是GC還算不得上優秀,按照GO的路線圖,後面會有更優秀的GC實現添加進來。

接口與struct。在第一次學習GO的interface的時候,我第一反應是這就是我想要的。雖然很多人也在說GO的這個interface的不好,而且說的很有道理,比如老趙的《爲什麼我不喜歡GO語言式的接口》。interface可以通過組合擴展爲新的interface,struct也可以通過組合擴展爲新的struct。沒有繼承,只有組合。可以通過匿名組合達到類似繼承的效果。可以對interface進行查詢,有點類似COM的味道,但是語法層面上更爲簡單。struct到interface的映射是隱式的,不需要聲明某個struct實現了某個interface。雖然可能會出現名字上的衝突,但是可以通過wrapper進行解決。這種interface的另外一個好處是單元測試時很容易實現MOCK,這點非常喜歡。也可以看這篇文章《Go interfaces make test stubbing easy》

統一的工作佈局。GO定義了項目的目錄結構,比如bin目錄,pkg目錄以及src目錄。這個和我日常的項目佈局是一致的。之前用C++開發時我們也是如此安排佈局,所以就這點來說,我覺着容易過渡。

內建的併發原語。提到GO就不得不提到goroutine和channel。廉價的goroutine可以讓我們歡快的處理異步任務,channel可以用來交換數據。藉助goroutine,可以很容易的實現高性能的服務端。goroutine及其調度器可以很容易和EPOLL,IOCP等系統機制結合起來,再通過Half Sync/Half Async模式,很容易在語法層面上達到同步形式,卻不失性能。

GO標準庫中還提供了sync包,其中有基本的mutex說,還有RMutex這樣的讀寫鎖,還有Once,WaiterGroup等東西。基本滿足日常中對鎖的需求了。

GO爲了幫助程序員解決在併發時經常遇到的race condition問題,還提供了相應的race condition工具。還有相應的死鎖檢測工具。

雖然GO社區有個slogan:"do not communicate by sharing memory; instead, share memory by communicating.",但是每個goroutine之間並不是完全獨立的,一樣可以做到通過內存共享數據。這個時候只能依靠程序員自己去遵守了。而且因爲goroutine不是完全獨立,panic這種東西就可能會導致整個程序掛掉。這點和Erlang比起來確實不是很好。

蛋疼的defer。用習慣了C++的RAII後,十分反感GO的defer機制,但是有的時候又不得不用。原因就是這個defer不是block級別的,而是函數級別的,需要在函數返回前纔得到執行。所以這就會導致在處理一些類似於文件打開,操作再關閉的邏輯時非常蛋疼,回到了C的年代,必須手動去Close。

蛋疼的panic。雖然我在C++下不怎麼用異常,但是對於panic這個設計我表示非常的不滿意啊。因爲它會影響全局。而要捕捉panic就需要用defer。如果panic只是讓當前goroutine掛掉我覺着就嗨皮壞了。

沒有泛型。GO沒有泛型帶來的蛋疼地方是,要麼就用interface{}來做運行時泛型,要麼就自己手動寫代碼生成器。比如我自己爲了生成網絡協議序列化代碼就擼了一個生成器。而且因爲沒有泛型,想實現類似C++ STL的容器與算法基本沒太可能,當然方法還是有的,繼續使用代碼生成器。而且GO1.4乾脆引入了一個叫go generate的命令。

總結
GO裏面其他一些內建的數據結構,比如slice,map等,但這些也是詬病,因爲它又沒給予程序員可以享用range關鍵字的福利。

在GO的所有特性裏,最喜歡就是GC,goroutine,channel以及interface。而其餘的特性(比如上面我列舉的很多特性)我覺着都不是太重要,其中很多都可以在工程中實踐,和語言本身沒有太大關係。

總結下來,這東西就是一個工程工具,各種好用,但是從設計角度講各種粗糙,沒必要過度高估。它算的上工程實踐中的好朋友。在寫服務端時,它是把利器,至少在寫服務端程序時,我自己感覺如此。

有朋友說一個語言好不好就看它有沒有開拓你的眼界,給予你新的思想,我想至少GO在這點上滿足了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章