Golang之美

Louyan發表於2018-11-21

初始golang,語言之美之簡潔之高效,天生具有高併發等特性。 本文來自蔡欣圻、邵聰聰,對go語言的分析很到位全面,在這裡分享出來給go開發者,希望能讓你有一個更深刻的認知。

目錄

  • Golang的哲學
  • Golang之美
  • Golang vs Java
  • 風靡世界?!
  • 我們的先行實踐

Golang的哲學


1、go背景介紹: go語言是google 2009年釋出的第二版開源程式語言,針對多處理器系統應用程式的程式設計進行了優化,使用Go編譯的程式可以媲美C或C++程式碼的速度,而且更加安全、支援並行程式。

2、go是面向介面、組合程式設計;

3、正交性:語言設計的正交性,保證語言的穩定性和簡單,go很好的遵循正交規律,如:goroutine介面、組合等;

4、少即是多:有且僅有一種方法把事情做好做對,保持簡單行的方法是go語言特性緊提供一種方法,減少重複、冗餘,把事情做到極致是go的原則;

5、併發語言層面支援:併發更好利用多核沒有更強的表現力來模擬真實世界;

6、開放性:開源,語言的實現對程式設計師不是個黑盒子,任何想了解語言實現都可以參與。

7、強大的作者陣容:C語言之父、Unix系統之父、Utf8和javascript V8之父等等

Golang之美


一、 可直接編譯成機器碼,不依賴其他庫,部署就是扔一個檔案上去就完成了

二、 編譯器和標準庫、三方庫都是Go語言實現,完全實現了語言上的自舉,任何人都可以輕鬆根據自己的需求修改原始碼,再也不用擔心去閱讀或者修改C或者C++實現的原始碼了

三、 靜態型別語言,靜態型別的語言就是可以在編譯的時候檢查出來隱藏的絕大多數問題

四、語言層面支援併發,這個就是Go最大的特色,天生的支援併發。天生的基因和整容是有區別的,大家一樣美麗,但是你喜歡整容的還是天生基因的美麗呢?Go就是基因裡面支援的併發,可以充分的利用多核,很容易的使用併發。

五、內建runtime、GC,從1.5開始GC已經逐漸趨於完美,下個版本1.8可以控制在海量儲存物件的場景下,保證1ms內的gc耗時

六、簡單易學,Go語言的作者都有C的基因,那麼Go自然而然就有了C的基因,那麼Go關鍵字是25個,但是表達能力很強大,幾乎支援 大多數你在其他語言見過的特性:繼承、多型、介面等。

七、豐富的標準庫,Go目前已經內建了大量的庫,特別是網路庫非常強大,是目前標準庫最強大的語言之一,基本上平時使用的所有功能都可以在標準庫中覓得身影。

八、完善的第三方生態環境,你所需要的所有功能都可以在第三方庫中找到,而且go的三方庫開發非常活躍,這個通過github的統計資料就可以得知,具體的三方庫部分列表可以通過awesome-go去檢視

九、跨平臺編譯 可以在任何一個平臺編譯其它所有系統和平臺的釋出版本,例如在mac上編譯windows、linux、plan9、fuchsia,編譯平臺包括i386、amd64、arm等等,所以go在物聯網和嵌入式領域特別有優勢,編譯出來的不僅體積小,而且無需安裝任何依賴就可以在嵌入式系統中執行

十、內嵌C、C++支援,前面說了作者是C的作者,所以Go裡面也可以直接包含c程式碼,利用現有的豐富的C庫,不過其實我們並不提倡這麼做,因為Go語言已經足夠快,也許只有在資料庫底層儲存這種場景需要呼叫C、C++函式去完成一些任務了。

十一、內建強大的工具 Go語言裡面內建了很多標準工具鏈,包括了程式碼格式化和風格提示、單元測試、Benchmark、系統profile、程式碼生成、文件生成等等。

例如,gofmt工具,自動化格式化程式碼,能夠讓團隊review變得如此的簡單,程式碼格式一模一樣,對於後續專案的維護非常有優勢。很多人都發現go的第三方庫的原始碼非常好閱讀,就是因為簡潔的語法和統一的程式碼風格。

下面附上Go自帶的標準profile工具生成的圖(在本地對遠端的伺服器進行profile),只需一行命令即可: 1、系統中各個函式的呼叫關係和CPU時間分佈圖:

go tool pprof -web http://xx.14.200:6001/debug/pprof/profile

Golang之美

2、記憶體使用大小分佈:

go tool pprof -web -alloc_space http://xx.7.14.200:6001/debug/pprof/heap

Golang之美

3、記憶體物件分配數分佈:

go tool pprof -web -alloc_objects http://xx.7.14.200:6001/debug/pprof/heap

Golang之美

4、強大、簡單的benchmark

程式碼:


package bench
import (
	    "testing"
)
// 測試Xor效能
func BenchmarkXor(b *testing.B) {
	a := 0
	for i := 0; i < b.N; i++ {
		final := 0
		for i := 0; i < 1000; i++ {
			final ^= i
		}
		a = final
	}
	_ = a
}      

複製程式碼
命令$: go test -v -run="none" -bench=. -benchmem -benchtime=‘3s’

結果 
BenchmarkXor-8   	20000000	       310 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	go_test/bench	6.537s
複製程式碼

Golang vs Java


1、物件導向比較:

一、 型別系統:

JAVA中有兩套完全獨立的型別系統,一套是值型別系統,byte、int、boolean、char、double另一套是以object型別為根的物件型別系統,Integer,HashMap等。值型別系統希望用object型別引用,則需要裝箱。而go語言中多數型別都是原生的值型別(避免裝箱可以節省大量的記憶體和CPU),甚至包括一些複合型別如陣列(array),結構體(struct)等,並且這些型別都可以有方法。我們可以給任何型別增加新方法。同時Go語言可以通過&獲得一個物件的引用如 var b=&a

二、記憶體排列:

Go因為沒有類例項物件這種東東,因此Go的任何變數在記憶體中都是緊密連續排列的,對於記憶體的訪問速度來說,親和度是很高的,而且CPU快取也更加容易命中。

三、成員的可訪問性:

Java中使用private,protected,public,package等關鍵字進行訪問控制。對於Go語言如果希望某個符號可被其他包(package)訪問,需要將該符號定義為大寫字母開頭。小寫字母開頭的符號只能在包內訪。

四、繼承:

Java的繼承通過extends關鍵字完成,不支援多繼承。Go語言的繼承通過匿名組合完成:基類以Struct的方式定義,子類只需要把基類作為成員放在子類的定義中,並且可以通過調整基類成員的位置改變記憶體佈局(因此Go語言相對其它高階語言可以對記憶體實現很精細的控制,減少記憶體佔用並提高效能)。

五、介面:

java中的介面作為不同元件中的契約存在,是強制的,類必須宣告實現了某介面,需要從該介面繼承。哪怕是兩個一模一樣的介面但只有名字不一樣,也只能根據類所宣告的實現介面是否包括該介面來決定該類是否實現該介面,叫做“侵入式”的介面。而GO語言中採用的是非侵入式介面,一個類只需要實現介面要求的所有函式,那我們就說該型別隱式實現了該介面,這個在使用第三方庫的時候非常易用,大大減少了庫之間的耦合度。GO語言可以通過介面進行介面查詢(介面指向的物件是否實現了另外的介面),型別查詢等

六、多型:

Java中的多型實現遵循一個原則:當超類物件引用變數引用子類物件時,被引用物件的型別而不是引用變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。Java中的多型可以通過基於繼承和基於介面兩種方法實現。而在go語言一般不允許不同型別的賦值,即不支援傳統的多型。interface是一個例外,可以用不同型別進行賦值只要一個型別實現了該介面,我們就可以將該型別的變數賦給該介面的變數。

2、多執行緒比較:

JAVA:

  1. JAVA 執行緒 與 OS 執行緒 1:1(其實這個是與虛擬機器實現有關,下面說的都是1:1模式),所以排程由系統來決定的(搶佔式)
  2. JAVA的執行緒可以設定Thread ID
  3. JAVA 的 棧是固定大小的
  4. JAVA 提供很多工具來除錯(包括執行期)
  5. 相對來說開銷要大很多
  6. new Thread(....).start();
  7. NIO效能很不錯,但是使用和實現起來複雜很多很多

GOLANG:

  1. Goroutine 是使用者態自己實現的執行緒,排程方式遇到IO/阻塞點方式就會讓出cpu時間(其實也看編譯器的實現,如果TA在程式碼裡面插入一些yield,也是可以的。 反正現在不是搶佔式的。)

  2. 不能設定goroutine ID, 也拿不到(可以呼叫C API或者自己修改原始碼暴漏出來,實際上修改起來挺簡單的,因為Go的原始碼寫的非常簡潔優雅)

  3. goroutine的棧會自動擴容(初始stack很小,2KB,這也是go程式記憶體佔用很小的原因) 4.相對java,多執行緒除錯工具鏈有待完善,不過我們目前也沒有發現需要這種除錯的地方,實在需要時通過profile工具和簡單的日誌就可以( 目前有一些第三方的工具,不過因為並不需要,我們也沒有使用過)

  4. 開銷非常小,同時執行幾百萬個一點問題都沒有

  5. go func(..) {} ()

  6. golang的最大特點就是這個goroutine非常簡單方便,實現功能,都只要按照人類最直接的思維模式寫就好(反正可以開大量的goroutine),不像回撥的方式那麼碎片化(nodejs),也遠遠不像NIO那麼複雜(netty).一句話:可以用最簡單的方式寫出來非常高效能的併發

  • golang多執行緒例子:

mian.go // 啟動海量子執行緒執行計算任務

package main
import (
	"log"
	"sync"
	"sync/atomic"
	"time"
)
var total int32 = 0
func main() {
	// 控制子執行緒的任務執行,等同於Map/Reduce處理
	wg := &sync.WaitGroup{}
	// 統計執行時間
	ts := time.Now()
	// 啟動100萬個執行緒,每個執行緒執行100次加1的任務,這裡使用了鎖,防止髒資料
             for i := 0; i < 1000000; i++ {
		// go標記的函式,自動在一個新的執行緒中去執行
		go func() {
		// 控制器的執行任務+1
                      wg.Add(1)
			// 子執行緒結束時,控制器的執行任務完成
			defer wg.Done()
			for i := 0; i < 100; i++ {
				atomic.AddInt32(&total, 1)
			}

		}()
	}
	
         // 這裡主執行緒休眠一小短時間,防止子執行緒的任務控制wg.Add(1)還沒有觸發,主執行緒就執行完畢
	time.Sleep(1 * time.Millisecond)

	// 等待子執行緒的任務完成
	wg.Wait()

	// 輸出最終執行時間
	log.Printf("啟動100萬個執行緒並執行計算任務完成,總計耗時:%v(毫秒)\n", time.Now().Sub(ts).Nanoseconds()/1000000)
	// 輸出最終結果
	log.Println("最終計算結果為", total)
}

結果:
2018/11/21 14:43:04 啟動100萬個執行緒並執行計算任務完成,總計耗時:2022(毫秒)
2018/11/21 14:43:04 最終計算結果為 100000000

複製程式碼

間隔執行$: go run main.go

間隔執行程式,會觀察到CPU的變化情況,go高併發自動呼叫CPU核數來實現執行緒

Golang之美

3.Web比較

這個應該是兩者區別最大的地方之一

Java: 使用Tomcat、jetty容器,或者使用netty中介軟體,也就是需要依賴第三方的東西

Golang: 只需要標準庫就可以實現很高很高的效能,我們目前用的http和http2、https服務、websocket服務、tcp服務、靜態檔案伺服器,在程式碼中都不會超過3行,非常非常簡潔,因為使用的標準庫,控制粒度非常細,可以說你就是自己程式碼的上帝

風靡世界?!


1、以下專案基本都是各自領域最火的專案之一,並且使用go作為最核心的語言

   CaaS : Docker , rkt等
   PaaS :  谷歌的k8s,flynn, deis等
複製程式碼

2、雲端儲存和儲存服務:

  dropbox(2年時間估值300多億美元),七牛雲、樂視雲
複製程式碼

3、資料庫:

  dgraph(谷歌的開源圖資料庫)、cockroach,codis, ,tidb,bolt,influxdb等
複製程式碼

4、Api閘道器:

    Apple的閘道器、百度的BFE等等
複製程式碼

5、監控平臺:

    小米、滴滴、攜程、360金融, influxdata(目前國外最後的開源系統監控解決方案),promethus
複製程式碼

6、軟負載均衡:

    谷歌的seesaw(替代lvs)
複製程式碼

7、中介軟體:

   服務發現:etcd,,consul
   訊息佇列:nsq, nats 
   搜尋: bleve(功能和ES一樣,也是基於lucence技術)
   mysql代理:  vitess(youtube的mysql proxy,作用等同於mycat,撐起了youtube的所有mysql請求), kingshard(金山的mysql proxy)
複製程式碼

8、安全平臺:

  vault
複製程式碼

9、CI(持續整合)平臺:

  drone
複製程式碼

10、Git web平臺:

  gogs(我們公司內部在使用的git服務)
複製程式碼

11、雲端計算虛擬網路vxlan層:

  flannel(效能是目前虛擬網路中最好的,跟物理網路效能幾乎差不多),之前h3c說的雲端計算虛擬網路層的核心就是vxlan,只不過h3c是自己實現的
複製程式碼

12、雲端計算基礎服務:

  IBM的z system、阿里雲的小部分服務,華為PaaS雲(研究院在對k8s進行二次開發)、網易容器雲、Cloud Foundry、UClound等等
複製程式碼

13、雲作業系統:

  coreos、plan9(這兩個系統的kernel和部分非常底層的功能是用C語言實現,其它部分很多都是Go語言實現)
複製程式碼

14、Saas雲服務:

  這個很多也很雜,國外的創業公司居多
複製程式碼

15、CDN:

  阿里、七牛、又拍雲、dropbox等等
複製程式碼

  • 直播平臺和視訊服務:阿里、bilibili、七牛、youtube、twitch、sex.com、facebook等等
  • 物聯網(IoT):SpaceX(遙感器平臺),gobot(機器人等IoT平臺)、Canopy等等,可以說Go是目前做IoT開發的最流行的語言之一
  • 區塊鏈技術: IBM的fabric,以太坊,比特幣,國內的幾個創業公司
  • 訊息和聊天平臺:360,bilibili等等,數不勝數
  • 新的傳輸層通訊協議: ipfs
  • 機器學習: golearn、tensoflow(官方自帶兩種語言api:python和go)
  • 語音智慧: 舜飛科技
  • VR: 愛奇藝正在祕密開發的VR平臺
  • 網約車服務: 滴滴(新的巴士事業部使用go作為首選核心語言,舊的業務也在逐步用go重寫)、uber(最核心也是併發最高的地圖圍欄演算法服務,業務層面每秒併發15萬以上,CPU和Web io雙密集型服務)
  • Web服務: SoundCloud、google,有贊、微信電影票、百度等等
  • 金融業: 廣發證券的實時行情分析系統是用Go重寫的,在高峰期也能保證非常低、非常穩定的處理延遲,這個對於證券行業非常重要、平安金融的部份基礎架構、銀匯的Web服務。
  • 同時go還是遊戲、dubo、色情等高併發行業的寵兒

我們的先行實踐


1.訊息推送和聊天平臺:宙斯,數萬行Go程式碼實現

2.通用Api閘道器

3.訊息統計平臺,為訊息推送和聊天平臺提供訊息查詢和統計服務,後面查詢服務會通過ELK來做

4.分散式UUID服務

5.支付通知中心

6.Apns蘋果推送

  1. 正在研發的開源監控平臺Vgo(這個目前是利用業餘時間私下在做的

我們的目標不僅僅是完成任務,更希望能通過開源打響傳化走向技術市場的第一炮!

相關文章