初始golang,語言之美之簡潔之高效,天生具備高併發等特性。 本文來自蔡欣圻、邵聰聰,對go語言的分析很到位全面,在這裏分享出來給go開發者,但願能讓你有一個更深入的認知。javascript
一、go背景介紹: go語言是google 2009年發佈的第二版開源編程語言,針對多處理器系統應用程序的編程進行了優化,使用Go編譯的程序能夠媲美C或C++代碼的速度,並且更加安全、支持並行進程。java
二、go是面向接口、組合編程;node
三、正交性:語言設計的正交性,保證語言的穩定性和簡單,go很好的遵循正交規律,如:goroutine接口、組合等;python
四、少便是多:有且僅有一種方法把事情作好作對,保持簡單行的方法是go語言特性緊提供一種方法,減小重複、冗餘,把事情作到極致是go的原則;mysql
五、併發語言層面支持:併發更好利用多核沒有更強的表現力來模擬真實世界;linux
六、開放性:開源,語言的實現對程序員不是個黑盒子,任何想了解語言實現均可以參與。git
七、強大的做者陣容:C語言之父、Unix系統之父、Utf8和javascript V8之父等等程序員
1、 可直接編譯成機器碼,不依賴其餘庫,部署就是扔一個文件上去就完成了github
2、 編譯器和標準庫、三方庫都是Go語言實現,徹底實現了語言上的自舉,任何人均可以輕鬆根據本身的需求修改源代碼,不再用擔憂去閱讀或者修改C或者C++實現的源碼了golang
3、 靜態類型語言,靜態類型的語言就是能夠在編譯的時候檢查出來隱藏的絕大多數問題
4、語言層面支持併發,這個就是Go最大的特點,天生的支持併發。天生的基因和整容是有區別的,你們同樣美麗,可是你喜歡整容的仍是天生基因的美麗呢?Go就是基因裏面支持的併發,能夠充分的利用多核,很容易的使用併發。
5、內置runtime、GC,從1.5開始GC已經逐漸趨於完美,下個版本1.8能夠控制在海量存儲對象的場景下,保證1ms內的gc耗時
6、簡單易學,Go語言的做者都有C的基因,那麼Go天然而然就有了C的基因,那麼Go關鍵字是25個,可是表達能力很強大,幾乎支持 大多數你在其餘語言見過的特性:繼承、多態、接口等。
7、豐富的標準庫,Go目前已經內置了大量的庫,特別是網絡庫很是強大,是目前標準庫最強大的語言之一,基本上平時使用的全部功能均可以在標準庫中覓得身影。
8、完善的第三方生態環境,你所須要的全部功能均可以在第三方庫中找到,並且go的三方庫開發很是活躍,這個經過github的統計數據就能夠得知,具體的三方庫部分列表能夠經過awesome-go去查看
9、跨平臺編譯 能夠在任何一個平臺編譯其它全部系統和平臺的發佈版本,例如在mac上編譯windows、linux、plan九、fuchsia,編譯平臺包括i38六、amd6四、arm等等,因此go在物聯網和嵌入式領域特別有優點,編譯出來的不只體積小,並且無需安裝任何依賴就能夠在嵌入式系統中運行
10、內嵌C、C++支持,前面說了做者是C的做者,因此Go裏面也能夠直接包含c代碼,利用現有的豐富的C庫,不過其實咱們並不提倡這麼作,由於Go語言已經足夠快,也許只有在數據庫底層存儲這種場景須要調用C、C++函數去完成一些任務了。
11、內置強大的工具 Go語言裏面內置了不少標準工具鏈,包括了代碼格式化和風格提示、單元測試、Benchmark、系統profile、代碼生成、文檔生成等等。
例如,gofmt工具,自動化格式化代碼,可以讓團隊review變得如此的簡單,代碼格式如出一轍,對於後續項目的維護很是有優點。不少人都發現go的第三方庫的源碼很是好閱讀,就是由於簡潔的語法和統一的代碼風格。
下面附上Go自帶的標準profile工具生成的圖(在本地對遠程的服務器進行profile),只需一行命令便可: 一、系統中各個函數的調用關係和CPU時間分佈圖:
go tool pprof -web http://xx.14.200:6001/debug/pprof/profile
二、內存使用大小分佈:
go tool pprof -web -alloc_space http://xx.7.14.200:6001/debug/pprof/heap
三、內存對象分配數分佈:
go tool pprof -web -alloc_objects http://xx.7.14.200:6001/debug/pprof/heap
四、強大、簡單的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
複製代碼
一、面向對象比較:
1、 類型系統:
JAVA中有兩套徹底獨立的類型系統,一套是值類型系統,byte、int、boolean、char、double另外一套是以object類型爲根的對象類型系統,Integer,HashMap等。值類型系統但願用object類型引用,則須要裝箱。而go語言中多數類型都是原生的值類型(避免裝箱能夠節省大量的內存和CPU),甚至包括一些複合類型如數組(array),結構體(struct)等,而且這些類型均可以有方法。咱們能夠給任何類型增長新方法。同時Go語言能夠經過&得到一個對象的引用如 var b=&a
2、內存排列:
Go由於沒有類實例對象這種東東,所以Go的任何變量在內存中都是緊密連續排列的,對於內存的訪問速度來講,親和度是很高的,並且CPU緩存也更加容易命中。
3、成員的可訪問性:
Java中使用private,protected,public,package等關鍵字進行訪問控制。對於Go語言若是但願某個符號可被其餘包(package)訪問,須要將該符號定義爲大寫字母開頭。小寫字母開頭的符號只能在包內訪。
4、繼承:
Java的繼承經過extends關鍵字完成,不支持多繼承。Go語言的繼承經過匿名組合完成:基類以Struct的方式定義,子類只須要把基類做爲成員放在子類的定義中,而且能夠經過調整基類成員的位置改變內存佈局(所以Go語言相對其它高級語言能夠對內存實現很精細的控制,減小內存佔用並提升性能)。
5、接口:
java中的接口做爲不一樣組件中的契約存在,是強制的,類必須聲明實現了某接口,須要從該接口繼承。哪怕是兩個如出一轍的接口但只有名字不同,也只能根據類所聲明的實現接口是否包括該接口來決定該類是否實現該接口,叫作「侵入式」的接口。而GO語言中採用的是非侵入式接口,一個類只須要實現接口要求的全部函數,那咱們就說該類型隱式實現了該接口,這個在使用第三方庫的時候很是易用,大大減小了庫之間的耦合度。GO語言能夠經過接口進行接口查詢(接口指向的對象是否實現了另外的接口),類型查詢等
6、多態:
Java中的多態實現遵循一個原則:當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,可是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。Java中的多態能夠經過基於繼承和基於接口兩種方法實現。而在go語言通常不容許不一樣類型的賦值,即不支持傳統的多態。interface是一個例外,能夠用不一樣類型進行賦值只要一個類型實現了該接口,咱們就能夠將該類型的變量賦給該接口的變量。
二、多線程比較:
JAVA:
GOLANG:
Goroutine 是用戶態本身實現的線程,調度方式遇到IO/阻塞點方式就會讓出cpu時間(其實也看編譯器的實現,若是TA在代碼裏面插入一些yield,也是能夠的。 反正如今不是搶佔式的。)
不能設置goroutine ID, 也拿不到(能夠調用C API或者本身修改源碼暴漏出來,實際上修改起來挺簡單的,由於Go的源碼寫的很是簡潔優雅)
goroutine的棧會自動擴容(初始stack很小,2KB,這也是go程序內存佔用很小的緣由) 4.相對java,多線程調試工具鏈有待完善,不過咱們目前也沒有發現須要這種調試的地方,實在須要時經過profile工具和簡單的日誌就能夠( 目前有一些第三方的工具,不過由於並不須要,咱們也沒有使用過)
開銷很是小,同時運行幾百萬個一點問題都沒有
go func(..) {} ()
golang的最大特色就是這個goroutine很是簡單方便,實現功能,都只要按照人類最直接的思惟模式寫就好(反正能夠開大量的goroutine),不像回調的方式那麼碎片化(nodejs),也遠遠不像NIO那麼複雜(netty).一句話:能夠用最簡單的方式寫出來很是高性能的併發
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核數來實現線程
3.Web比較
這個應該是二者區別最大的地方之一
Java: 使用Tomcat、jetty容器,或者使用netty中間件,也就是須要依賴第三方的東西
Golang: 只須要標準庫就能夠實現很高很高的性能,咱們目前用的http和http二、https服務、websocket服務、tcp服務、靜態文件服務器,在代碼中都不會超過3行,很是很是簡潔,由於使用的標準庫,控制粒度很是細,能夠說你就是本身代碼的上帝
一、如下項目基本都是各自領域最火的項目之一,而且使用go做爲最核心的語言
CaaS : Docker , rkt等
PaaS : 谷歌的k8s,flynn, deis等
複製代碼
二、雲存儲和存儲服務:
dropbox(2年時間估值300多億美圓),七牛雲、樂視雲
複製代碼
三、數據庫:
dgraph(谷歌的開源圖數據庫)、cockroach,codis, ,tidb,bolt,influxdb等
複製代碼
四、Api網關:
Apple的網關、百度的BFE等等
複製代碼
五、監控平臺:
小米、滴滴、攜程、360金融, influxdata(目前國外最後的開源系統監控解決方案),promethus
複製代碼
六、軟負載均衡:
谷歌的seesaw(替代lvs)
複製代碼
七、中間件:
服務發現:etcd,,consul
消息隊列:nsq, nats
搜索: bleve(功能和ES同樣,也是基於lucence技術)
mysql代理: vitess(youtube的mysql proxy,做用等同於mycat,撐起了youtube的全部mysql請求), kingshard(金山的mysql proxy)
複製代碼
八、安全平臺:
vault
複製代碼
九、CI(持續集成)平臺:
drone
複製代碼
十、Git web平臺:
gogs(咱們公司內部在使用的git服務)
複製代碼
十一、雲計算虛擬網絡vxlan層:
flannel(性能是目前虛擬網絡中最好的,跟物理網絡性能幾乎差很少),以前h3c說的雲計算虛擬網絡層的核心就是vxlan,只不過h3c是本身實現的
複製代碼
十二、雲計算基礎服務:
IBM的z system、阿里雲的小部分服務,華爲PaaS雲(研究院在對k8s進行二次開發)、網易容器雲、Cloud Foundry、UClound等等
複製代碼
1三、雲操做系統:
coreos、plan9(這兩個系統的kernel和部分很是底層的功能是用C語言實現,其它部分不少都是Go語言實現)
複製代碼
1四、Saas雲服務:
這個不少也很雜,國外的創業公司居多
複製代碼
1五、CDN:
阿里、七牛、又拍雲、dropbox等等
複製代碼
1.消息推送和聊天平臺:宙斯,數萬行Go代碼實現
2.通用Api網關
3.消息統計平臺,爲消息推送和聊天平臺提供消息查詢和統計服務,後面查詢服務會經過ELK來作
4.分佈式UUID服務
5.支付通知中心
6.Apns蘋果推送
咱們的目標不只僅是完成任務,更但願能經過開源打響傳化走向技術市場的第一炮!