golang 快速入門 [1]-go 語言導論

weishixianglian發表於2020-03-10

golang 快速入門 [1]-go 語言導論

宣告

  • 這是一套幫助初學者從 0 到 1 學習 go 語言的開源教程,致力於打造最完整、最強悍、最有深度的 Go 語言學習體系
  • 我希望這套課程能夠涵蓋 Go 語言的所有體系、並致力於用大量的案例來詮釋其用法
  • 鑑於作者水平有限,真誠地希望能夠集所有人的智慧,完善此專案,連結附後

簡介

  • Go(又稱 Golang)是 Google 開發的一種靜態強型別、編譯型、併發型,並具有垃圾回收功能的程式語言
  • Go 的最初目標是消除 Google 軟體開發的緩慢性和笨拙性,從而使流程更具效率和可擴充套件性,更多的關注於軟體工程領域
  • Go 致力於解決當代大型工程專案面臨的多核處理,網路系統,海量計算叢集、快速構建等問題,Go 在語言級別考慮併發問題,提供簡單高效的併發程式設計
  • 羅伯特·格瑞史莫 (Robert Griesemer),羅勃·派克(Rob Pike)及肯·湯普遜 (Ken Thompson) 於 2007 年 9 月開始設計 Go,稍後 Ian Lance Taylor、Russ Cox 加入專案
  • Go 是基於 Inferno 作業系統所開發的
  • Go 於 2009 年 11 月正式宣佈推出,成為開放原始碼專案,支援 Linux、macOS、Windows 等作業系統
  • 在 2016 年,Go 被軟體評價公司 TIOBE 選為 “TIOBE 2016 年最佳語言”
  • 很多重要的開源專案都是使用 Go 語言開發的,其中包括 Docker、Go-Ethereum、Thrraform、Kubernetes、etcd、hyperledger、tidb

基本語言的歷史

  • 1960 年 Ken Thompson(肯.湯普森) 發明了 B 語言
  • 1972 年 Dennis Ritchie(丹尼斯·裡奇) 發明了 C 語言
  • 1982 年 Bjarne Stroustrup(本賈尼) 發明了 C++ 語言
  • 1989 年 Guido von Rossum 發明了 Python 語言
  • 1995 年 SUN 公司發明了 Java 語言
  • 2007 年 Go 語言誕生
  • 2009 年的 11 月對外正式釋出

Go 語言創始人

對語言進行評估時,明白設計者的動機以及語言要解決的問題很重要。Go 語言出自 Ken Thompson 和 Rob Pike、Robert Griesemer 之手,他們都是電腦科學領域的重量級人物。

  • Ken Thompson 貝爾實驗室 Unix 團隊成員,C 語言、Unix 和 Plan 9 的創始人之一,在 20 世紀 70 年代,設計並實現了最初的 UNIX 作業系統,僅從這一點說,他對電腦科學的貢獻怎麼強調都不過分。他還與 Rob Pike 合作設計了 UTF-8 編碼方案
  • Rob Pike Go 語言專案總負責人,貝爾實驗室 Unix 團隊成員,除幫助設計 UTF-8 外,還幫助開發了分散式多使用者作業系統 Plan 9、Inferno 作業系統和 Limbo 程式語言,並與人合著了《The Unix Programming Environment》,對 UNIX 的設計理念做了正統的闡述
  • Robert Griesemer 就職於 Google,參與開發 Java HotSpot 虛擬機器,對語言設計有深入的認識,並負責 Chrome 瀏覽器和 Node.js 使用的 Google V8 JavaScript 引擎的程式碼生成部分

go 語言的繼承

  • Go 語言有時候被描述為 “C 類似語言”,或者是 “21 世紀的 C 語言”
  • Go 從 C 語言繼承了相似的表示式語法、控制流結構、基礎資料型別、呼叫引數傳值、指標等思想
  • Go 繼承了 C 語言一直所看中的編譯後機器碼的執行效率以及和現有作業系統的無縫適配
  • Go 語言的家族樹中還有其它的祖先。其中一個有影響力的分支來自 Niklaus Wirth 所設計的 Pascal 語言
  • Modula-2 語言激發了包的概念,然後 Oberon 語言摒棄了模組介面檔案和模組實現檔案之間的區別。第二代的 Oberon-2 語言直接影響了包的匯入和宣告的語法,還有 Oberon 語言的物件導向特性所提供的方法的宣告語法等
  • Go 語言的另一支祖先,帶來了 Go 語言區別其他語言的重要特性,靈感來自於貝爾實驗室的 Tony Hoare 於 1978 年發表的鮮為外界所知的關於併發研究的基礎文獻順序通訊程式(communicating sequential processes,縮寫為 CSP) 在 CSP 中,程式是一組中間沒有共享狀態的平行執行的處理過程,它們之間使用管道進行通訊和控制同步。不過 Tony Hoare 的 CSP 只是一個用於描述併發性基本概念的描述語言,並不是一個可以編寫可執行程式的通用程式語言 Rob Pike 和其他人開始不斷嘗試將 CSP 引入實際的程式語言中。他們第一次嘗試引入 CSP 特性的程式語言叫 Squeak,是一個提供滑鼠和鍵盤事件處理的程式語言,它的管道是靜態建立的 然後是改進版的 Newsqueak 語言,提供了類似 C 語言語句和表示式的語法和類似 Pascal 語言的推導語法。Newsqueak 是一個帶垃圾回收的純函式式語言,它再次針對鍵盤、滑鼠和視窗事件管理。在 Newsqueak 語言中管道是動態建立的,屬於第一等公民,可以儲存到變數中 在 Plan9 作業系統中,這些優秀的想法被吸收到了一個叫 Alef 的程式語言中。Alef 試圖將 Newsqueak 語言改造為系統程式語言,但是因為缺少垃圾回收機制而導致併發程式設計很痛苦 注:在 Aelf 之後還有一個叫 Limbo 的程式語言,Go 語言從其中借鑑了很多特性。具體請參考 Pike 的講稿:http://talks.golang.org/2012/concurrency.slide#9
  • Go 語言的其他的一些特性零散地來自於其他一些程式語言;比如 iota 語法是從 APL 語言借鑑,詞法作用域與巢狀函式來自於 Scheme 語言和其他很多語言
  • Go 中也有很多創新的設計,比如 Go 語言的切片為動態陣列提供了有效的隨機存取的效能,還有 Go 語言新發明的 defer 語句

go 語言的特點

所有的程式語言都反映了語言設計者對程式設計哲學的反思,通常包括之前的語言所暴露的一些不足地方的改進。

  • 簡潔 Go 專案是在 Google 公司維護超級複雜的幾個軟體系統遇到的一些問題的反思(但是這類問題絕不是 Google 公司所特有的) 正如 Rob Pike 所說,“軟體的複雜性是乘法級相關的”,通過增加一個部分的複雜性來修復問題通常將慢慢地增加其他部分的複雜性 通過增加功能、選項、配置是修復問題的最快的途徑,但是這很容易讓人忘記簡潔的內涵,卽使從長遠來看,簡潔依然是好軟體的關鍵因素 簡潔的設計需要在工作開始的時候捨棄不必要的想法,並且在軟體的生命週期內嚴格區別好的改變或壞的改變。通過足夠的努力,一個好的改變可以在不破壞原有完整概念的前提下保持自適應 而一個壞的改變則不能達到這個效果,它們僅僅是通過膚淺的和簡單的妥協來破壞原有設計的一致性。只有通過簡潔的設計,才能讓一個系統保持穩定、安全和持續的進化 附帶了相關的工具和標準庫 沒有隱式的數值轉換 沒有建構函式和解構函式 沒有運算子過載 沒有預設引數 沒有繼承 沒有泛型(go2 中考慮加入) 沒有異常,即沒有與錯誤處理相關的控制結構 沒有巨集 沒有函式修飾 沒有執行緒區域性儲存。 沒有指標運算 沒有型別別名 陣列邊界總是受到檢查
  • 基本特性 自動垃圾回收 包管理 函式作為一等公民 系統呼叫介面 只讀的 UTF8 字串 函式多返回值 匿名函式和閉包 反射 靜態連結 嚴格的依賴規範 CSP 併發程式設計 Goroutine 協程 介面型別
  • 向後相容 Go 語言本身是成熟和穩定的,而且承諾保證向後相容:用之前的 Go 語言編寫程式可以用新版本的 Go 語言編譯器和標準庫直接構建而不需要修改程式碼
  • 型別系統 相比較於 js、python,Go 語言的型別系統避免動態語言中那些粗心的型別錯誤。但是 Go 語言的型別系統相比傳統的強型別語言又要簡潔很多,雖然有時候這會導致一個 “無型別” 的抽象型別的概念 Go 語言程式設計師並不需要像 C++ 或 Haskell 程式設計師那樣糾結於具體型別的安全屬性。在實踐中 Go 語言簡潔的型別系統給了程式設計師帶來了更多的安全性和更好的執行時效能 Go 語言遵循當代計算機系統設計的原則,特別是區域性的重要性。Go 的內建資料型別和大多數的標準資料結構都經過精心設計而避免顯式的初始化或隱式的建構函式,因此記憶體分配和記憶體初始化程式碼被隱藏在庫程式碼中了 Go 語言的聚合型別(結構體和陣列)可以直接操作它們的元素,只需要更少的儲存空間、更少的記憶體分配,而且指標操作比其他間接操作的語言也更有效率
  • 併發支援 由於現代計算機是一個並行的機器,Go 語言提供了基於 CSP 的併發特性支援。Go 語言的動態棧使得輕量級執行緒 goroutine 的初始棧可以很小,因此建立一個 goroutine 的代價很小,建立百萬級的 goroutine 完全是可行的。 Go 併發的座右銘:不要通過共享記憶體進行通訊,而要通過通訊共享記憶體(Don't communicate by sharing memory, share memory by communicating)
  • 自動垃圾回收機制 對於系統語言,垃圾回收可能是一個有爭議的功能 Go 沒有顯式的記憶體釋放操作:分配的記憶體返回池的唯一方法是通過垃圾回收器。 記憶體管理對語言在實踐中的工作方式具有深遠的影響。在 C 和 C++ 中,太多的程式設計工作花費在記憶體分配和釋放上 由於垃圾回收機制,語言更易於使用。 垃圾回收會帶來巨大的成本:常規開銷,延遲和實現的複雜性 知識淵博的程式設計師可以限制收集器所承受的壓力,從而提高效能。(此外,Go 安裝附帶了用於研究正在執行的程式的動態記憶體效能的良好工具) 自動垃圾回收演算法是一個持續跟新的過程、活躍的開發領域
  • 強大的標準庫與規範 Go 語言的標準庫,提供了清晰的構建模組和公共介面,包含 I/O 操作、文字處理、影像、密碼學、網路和分散式應用程式等,並支援許多標準化的檔案格式和編解碼協議 庫和工具使用了大量的約定來減少額外的配置和解釋,從而最終簡化程式的邏輯,而且每個 Go 程式結構都是如此的相似,因此 Go 程式也很容易學習 Go 語言自帶工具構建 Go 語言專案只需要使用檔名、識別符號名稱以及少量的註釋確定所有的庫、可執行檔案、測試、基準測試、案例、以及特定於平臺的變數、專案的文件等;Go 語言原始碼本身就包含了構建規範
  • 開源,活躍的社群
  • 組成而不是繼承 Go 採用一種不尋常的方法來進行物件導向的程式設計(介面),它允許有相同方法的任何型別繼承,而不僅是類 Go 沒有任何形式的基於型別的繼承,這意味著沒有型別層次結構 這是一個故意的設計選擇,儘管型別層次結構已用於構建許多成功的軟體,但 Go 認為該模型已被過度使用 ## Go 語言的優勢
  • 學習曲線容易,語法簡單清晰 單就型別和規則而言,Go 與 C99、C11 相似之處頗多,這也是 Go 語言被冠以 “NextC” 名號的重要原因。 Go 語言的語法規則嚴謹,沒有歧義,更沒什麼黑魔法變異用法。 任何人寫出的程式碼都基本一致,這使得 Go 語言簡單易學。放棄部分 “靈活” 和 “自由”,換來更好的維護性
  • 強大的標準庫和工具鏈 完整的工具鏈對於日常開發極為重要。Go 在此做得相當不錯,無論是編譯、格式化、錯誤檢查、幫助文件,還是第三方包下載、更新都有對應的工具 內建完整測試框架,其中包括單元測試、效能測試、程式碼覆蓋率、資料競爭,以及用來調優的 pprof,這些都是保障程式碼能正確而穩定執行的必備利器 可通過環境變數輸出執行時監控資訊,尤其是垃圾回收和併發排程跟蹤,可進一步幫助我們改進演算法,獲得更佳的執行期表現
  • 自動垃圾回收機制 垃圾回收一直是個難題。早年間,Java 就因垃圾回收低效被嘲笑了許久,後來 Sun 連續收納了好多人和技術才發展到今天。可即便如此,在 Hadoop 等大記憶體應用場景下,垃圾回收依舊捉襟見肘、步履維艱 相比 Java,Go 面臨的困難要更多。因指標的存在,所以回收記憶體不能做收縮處理。幸好,指標運算被阻止,否則要做到精確回收都難 每次升級,垃圾回收器必然是核心元件裡修改最多的部分。從併發清理,到降低 STW 時間,直到 Go 的 1.5 版本實現併發標記,逐步引入三色標記和寫屏障等等,都是為了能讓垃圾回收在不影響使用者邏輯的情況下更好地工作
  • 靜態連結 執行時、依賴庫直接打包到可執行檔案內部,簡化了部署和釋出操作,無須事先安裝執行環境和下載諸多第三方庫
  • 編譯迅速
  • 清晰的依賴關係
  • 併發程式設計 在早期 CPU 都是以單核的形式順序執行機器指令。Go 語言的祖先 C 語言正是這種順序程式語言的代表 隨著處理器技術的發展,單核時代以提升處理器頻率來提高執行效率的方式遇到了瓶頸,單核 CPU 發展的停滯,給多核 CPU 的發展帶來了機遇 現代計算機都擁有多個核,但是大部分程式語言都沒有有效的工具讓程式可以輕易利用這些資源。程式設計時需要寫大量的執行緒同步程式碼來利用多個核,很容易導致錯誤 Go 語言正是在多核和網路化的時代背景下誕生的原生支援併發的程式語言。Go 語言從底層原生支援併發,無須第三方庫,開發人員可以很輕鬆地在編寫程式時決定怎麼使用 CPU 資源 Goroutine 是 Go 最顯著的特徵 Go 語言的併發是基於 goroutine 的,goroutine 類似於執行緒,但並非執行緒。可以將 goroutine 理解為一種虛擬執行緒。Go 語言執行時會參與排程 goroutine,並將 goroutine 合理地分配到每個 CPU 中,最大限度地使用 CPU 效能 Go 用類協程的方式來處理併發單元,卻又在執行時層面做了更深度的優化處理。這使得語法上的併發程式設計變得極為容易 無須處理回撥,無須關注執行緒切換,僅一個關鍵字,簡單而自然 搭配 channel,實現 CSP 模型。將併發單元間的資料耦合拆解開來,各司其職,這對所有糾結於記憶體共享、鎖粒度的開發人員都是一個可期盼的解脫
  • 記憶體分配 Go 選擇了 tcmalloc,它本就是為併發而設計的高效能記憶體分配元件 刨去因配合垃圾回收器而修改的內容,記憶體分配器完整保留了 tcmalloc 的原始架構。使用 cache 為當前執行執行緒提供無鎖分配,多個 central 在不同執行緒間平衡記憶體單元複用 heap 則管理著大塊記憶體,用以切分成不同等級的複用記憶體塊。快速分配和二級記憶體平衡機制,讓記憶體分配器能優秀地完成高壓力下的記憶體管理任務

Go 語言擅長的領域

  • Go 語言主要用作伺服器端開發,適合於多人週期較長的大型軟體和支援雲端計算的網路服務
  • 在伺服器程式設計方面,Go 語言適合處理日誌、中介軟體、資料打包、虛擬機器處理、檔案系統、分散式系統、資料庫代理等
  • 網路程式設計方面,Go 語言廣泛應用於 Web 應用、API 應用、下載應用等
  • 此外,Go 語言還可用於記憶體資料庫和雲平臺領域,目前國外很多雲平臺都是採用 Go 開發
  • 由於 Go 垃圾回收犧牲了一些效能,因此其不適合做作業系統程式設計以及對速度要求極致的程式,不適合直接處理資料分析與計算

使用 Go 語言的公司

參見世界上使用 Go 語言的企業

  • Google 作為創造了 Go 語言的 google 公司,當然會力挺 Go 語言了。Google 有很多基於 Go 開發的開源專案,比如 kubernets,docker,大家可以參考《哪些專案使用 Go 語言開發》一節瞭解更多的 Go 語言開源專案
  • Facebook Facebook 也在使用 Go 語言,為此他們還專門在 Github 上建立了一個開源組織 facebookgo。大家可以通過 https://github.com/facebookgo 訪問檢視 facebook 開源的專案,其中最具代表性的就是著名平滑重啟工具 grace
  • 騰訊 騰訊在 15 年就已經做了 Docker 萬臺規模的實踐。因為騰訊主要的開發語言是 C/C++ ,所以在使用 Go 語言方面會方便很多,也有很多優勢,不過日積月累的 C/C++ 程式碼很難改造,也不敢動,所以主要在新業務上嘗試使用 Go
  • 百度 百度主要在運維方面使用到了 Go 語言,比如百度運維的一個 BFE 專案,主要負責前端流量的接入,其次就是百度訊息通訊系統的伺服器端也使用到了 Go 語言
  • 七牛雲 七牛雲算是國內第一家選 Go 語言做服務端的公司。早在 2011 年,當 Go 語言的語法還沒完全穩定下來的情況下,七牛雲就已經選擇將 Go 作為儲存服務端的主體語言
  • 京東 京東雲訊息推送系統、雲端儲存,以及京東商城的列表頁等都是使用 Go 語言開發的
  • 小米 小米對 Go 語言的支援,在於運維監控系統的開源,它的官方網址是 http://open-falcon.org/Go 語言。此外,小米互娛、小米商城、小米視訊、小米生態鏈等團隊都在使用
  • 360 360 對 Go 語言的使用也不少,比如開源的日誌搜尋系統 Poseidon,大家可以通過 https://github.com/Qihoo360/poseidon 檢視,還有 360 的推送團隊也在使用 Go 語言 除了上面提到的,還有很多公司開始嘗試使用 Go 語言,比如美團、滴滴、新浪等。

Go 語言吉祥物

Go 語言有一個吉祥物,在會議、文件頁面和博文中,大多會包含下圖所示的 Go Gopher,這是才華橫溢的插畫家 Renee French 設計的,她也是 Go 設計者之一 Rob Pike 的妻子。

參考資料

更多原創文章乾貨分享,請關注公眾號
  • golang 快速入門 [1]-go 語言導論
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章