<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么要了解Go語言編譯器?

          共 5458字,需瀏覽 11分鐘

           ·

          2021-09-21 17:20

          編譯器是一個大型且復雜的系統(tǒng),一個好的編譯器會很好地結合形式語言理論、算法、人工智能、系統(tǒng)設計、計算機體系結構及編程語言理論。Go語言的編譯器遵循了主流編譯器采用的經(jīng)典策略及相似的處理流程和優(yōu)化規(guī)則(例如經(jīng)典的遞歸下降的語法解析、抽象語法樹的構建)。另外,Go語言編譯器有一些特殊的設計,例如內(nèi)存的逃逸等。

          編譯原理值得用一本書的筆墨去講解,通過了解Go語言編輯器,不僅可以了解大部分高級語言編譯器的一般性流程與規(guī)則,也能指導我們寫出更加優(yōu)秀的程序。很多Go語言的語法特性都離不開編譯時與運行時的共同作用。另外,如果讀者希望開發(fā)go import、go fmt、go lint等掃描源代碼的工具,那么同樣離不開編譯器的知識和Go語言提供的API。

          Go語言編譯器的階段

          如圖1-1所示,在經(jīng)典的編譯原理中,一般將編譯器分為編譯器前端、優(yōu)化器和編譯器后端。這種編譯器被稱為三階段編譯器(three-phase compiler)。其中,編譯器前端主要專注于理解源程序、掃描解析源程序并進行精準的語義表達。編譯器的中間階段(Intermediate Representation,IR)可能有多個,編譯器會使用多個IR階段、多種數(shù)據(jù)結構表示代碼,并在中間階段對代碼進行多次優(yōu)化。例如,識別冗余代碼、識別內(nèi)存逃逸等。編譯器的中間階段離不開編譯器前端記錄的細節(jié)。編譯器后端專注于生成特定目標機器上的程序,這種程序可能是可執(zhí)行文件,也可能是需要進一步處理的中間形態(tài)obj文件、匯編語言等。

          1-1  三階段編譯器

          需要注意的是,編譯器優(yōu)化并不是一個非常明確的概念。優(yōu)化的主要目的一般是降低程序資源的消耗,比較常見的是降低內(nèi)存與CPU的使用率。但在很多時候,這些目標可能是相互沖突的,對一個目標的優(yōu)化可能降低另一個目標的效率。同時,理論已經(jīng)表明有一些代碼優(yōu)化存在著NP難題,這意味著隨著代碼的增加,優(yōu)化的難度將越來越大,需要花費的時間呈指數(shù)增長。因為這些原因,編譯器無法進行最佳的優(yōu)化,所以通常采用一種折中的方案。

          Go語言編譯器一般縮寫為小寫的gc(go compiler),需要和大寫的GC(垃圾回收)進行區(qū)分。Go語言編譯器的執(zhí)行流程可細化為多個階段,包括詞法解析、語法解析、抽象語法樹構建、類型檢查、變量捕獲、函數(shù)內(nèi)聯(lián)、逃逸分析、閉包重寫、遍歷函數(shù)、SSA生成、機器碼生成,如圖1-2所示。


          1- Go語言編譯器執(zhí)行流程


          詞法解析

          和Go語言編譯器有關的代碼主要位于src/cmd/compile/internal目錄下,在后面分析中給出的文件路徑均默認位于該目錄中。在詞法解析階段,Go語言編譯器會掃描輸入的Go源文件,并將其符號(token)化。例如“+”和“-”操作符會被轉(zhuǎn)換為_IncOp,賦值符號“:= ”會被轉(zhuǎn)換為_Define。這些token實質(zhì)上是用iota聲明的整數(shù),定義在syntax/tokens.go中。符號化保留了Go語言中定義的符號,可以識別出錯誤的拼寫。同時,字符串被轉(zhuǎn)換為整數(shù)后,在后續(xù)的階段中能夠被更加高效地處理。圖1-3為一個示例,展現(xiàn)了將表達式a:=b + c(12)符號化之后的情形。代碼中聲明的標識符、關鍵字、運算符和分隔符等字符串都可以轉(zhuǎn)化為對應的符號。



          圖1-3  Go語言編譯器詞法解析示例


          Go語言標準庫go/scanner、go/token也提供了許多接口用于掃描源代碼。在下例中,我們將使用這些接口模擬對Go文本文件的掃描。

          package mainimport (    "fmt"    "go/scanner"    "go/token")func main() {    src := []byte("cos(x) + 2i*sin(x) // Euler")
          // 初始化 scanner var s scanner.Scanner fset := token.NewFileSet() file := fset.AddFile("", fset.Base(), len(src)) s.Init(file, src, nil , scanner.ScanComments) // 掃描 for { pos, tok, lit := s.Scan() if tok == token.EOF { break } fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit) }}


          在上例中,src為進行詞法掃描的表達式,可以將其模擬為一個文件并調(diào)用scanner.Scanner詞法,掃描后分別打印出token的位置、符號及其字符串字面量。每個標識符與運算符都被特定的token代替,例如2i被識別為復數(shù)IMAG,注釋被識別為COMMENT。

          1:1     IDENT   "cos"1:4     (       ""1:5     IDENT   "x"1:6     )       ""1:8     +       ""1:10    IMAG    "2i"1:12    *       ""1:13    IDENT   "sin"1:16    (       ""1:17    IDENT   "x"1:18    )       ""1:20    ;       "\n"1:20    COMMENT "http:// Euler"


          語法解析

          詞法解析階段結束后,需要根據(jù)Go語言中指定的語法對符號化后的Go文件進行解析。Go語言采用了標準的自上而下的遞歸下降(Top-Down Recursive-Descent)算法,以簡單高效的方式完成無須回溯的語法掃描,核心算法位于syntax/nodes.go及syntax/parser.go中。圖1-4為Go語言編譯器對文件進行語法解析的示意圖。在一個Go源文件中主要有包導入聲明(import)、靜態(tài)常量(const)、類型聲明(type)、變量聲明(var)及函數(shù)聲明。


          圖1-4  Go語言編譯器對文件進行語法解析的示意圖


          源文件中的每一種聲明都有對應的語法,遞歸下降通過識別初始的標識符,例如_const,采用對應的語法進行解析。這種方式能夠較快地解析并識別可能出現(xiàn)的語法錯誤。每一種聲明語法在Go語言規(guī)范中都有定義

          //包導入聲明ImportSpec = [ "." | PackageName ] ImportPath .ImportPath = string_lit .// 靜態(tài)常量ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .//類型聲明TypeSpec = identifier [ "=" ] Type .//變量聲明VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .

          函數(shù)聲明是文件中最復雜的一類語法,因為在函數(shù)體的內(nèi)部可能有多種聲明、賦值(例如:= )、表達式及函數(shù)調(diào)用等。例如defer語法為defer Expression ,其后必須跟一個函數(shù)或方法。每一種聲明語法或者表達式都有對應的結構體,例如a := b + f(89) 對應的結構體為賦值聲明AssignStmt。Op代表當前的操作符,即“ :=”, Lhs與Rhs分別代表左右兩個表達式。

          AssignStmt struct {        Op       Operator         Lhs, Rhs Expr             simpleStmt    }


          語法解析丟棄了一些不重要的標識符,例如括號“ (”,并將語義存儲到了對應的結構體中。語法聲明的結構體擁有對應的層次結構,這是構建抽象語法樹的基礎。圖1-5為a := b + c(12)語句被語法解析后轉(zhuǎn)換為對應的syntax.AssignStmt結構體之后的情形。最頂層的Op操作符為token.Def(:= )。Lhs表達式類型為標識符syntax.Name,值為標識符“a”。Rhs表達式為syntax.Operator加法運算。加法運算左邊為標識符“b”,右邊為函數(shù)調(diào)用表達式,類型為CallExpr。其中,函數(shù)名c的類型為syntax.Name,參數(shù)為常量類型syntax.BasicLit,代表數(shù)字12。


          圖1-5  特定表達式的語法解析示例


          Go語言可執(zhí)行文件的生成離不開編譯器所做的復雜工作,如果不理解Go語言的編譯器,那么對Go語言的理解是不完整的。Go語言的編譯器、運行時,本身就是用Go語言寫出的既復雜又精巧的程序;探究語言設計、語法特性,本身就是學習程序設計與架構、數(shù)據(jù)結構與算法等知識的絕佳途徑。學習底層原理能夠幫助我們更好地了解Go語言的語法,做出合理的性能優(yōu)化,設計科學的程序架構,監(jiān)控程序的運行狀態(tài),排查復雜的程序異常問題,開發(fā)出檢查協(xié)程泄露、語法等問題的高級工具,理解Go語言的局限性,從而在不同場景下做出合理抉擇。

          編譯階段包括詞法解析、語法解析、抽象語法樹構建、類型檢查、變量捕獲、函數(shù)內(nèi)聯(lián)、逃逸分析、閉包重寫、遍歷并編譯函數(shù)、SSA生成、機器碼生成。編譯器不僅能準確地表達語義,還能對代碼進行一定程度的優(yōu)化。可以看到,Go語言的很多語法檢查、語法特性都依賴編譯時。理解編譯時的基本流程、優(yōu)化方案及一些調(diào)試技巧有助于寫出更好的程序。

          目前市面上鮮有系統(tǒng)介紹Go語言底層實現(xiàn)原理的書籍,如果你想系統(tǒng)了解學習更多,今天給大家推薦這本新書書,書中系統(tǒng)性地介紹Go語言在編譯時、運行時以及語法特性等層面的底層原理和更好的使用方法。

          本書語言通俗易懂,書中有系統(tǒng)權威的知識解構、精美的示意圖,并對照源碼和參考文獻字斟句酌,在一線大規(guī)模系統(tǒng)中提煉出設計哲學與避坑方法,對于編譯時、運行時及垃圾回收的精彩講解彌補了國內(nèi)的多項缺陷,這本罕見的誠意之作必將陪伴讀者實現(xiàn)最艱苦的能力跨越,你想要的都會到來……

          內(nèi)容簡介

          本書由21章組成,這21章可以分為6部分。

          • 第1~8章為第1部分,介紹Go語言的基礎——編譯時及類型系統(tǒng)。包括浮點數(shù)、切片、哈希表等類型以及類型轉(zhuǎn)換的原理。

          • 第9~11章為第2部分,介紹程序運行重要的組成部分——函數(shù)與棧。包括棧幀布局、棧擴容、棧調(diào)試的原理,并介紹了延遲調(diào)用、異常與異常捕獲的原理。

          • 第12、13章為第3部分,介紹Go語言程序設計的關鍵——接口。包括如何正確合理地使用接口構建程序、接口的實現(xiàn)原理和可能遇到的問題,并探討了接口之上的反射原理。

          • 第14~17章為第4部分,介紹Go語言并發(fā)的核心——協(xié)程與通道。詳細論述了協(xié)程的本質(zhì)以及運行時調(diào)度器的調(diào)度時機與策略。介紹了通過通信來共享內(nèi)存的通道本質(zhì)以及通道的多路復用原理,并探討了并發(fā)控制、數(shù)據(jù)爭用問題的解決辦法及鎖的本質(zhì)。

          • 第18~20章為第5部分,介紹Go語言運行時最復雜的模塊——內(nèi)存管理與垃圾回收。詳細論述了Go語言中實現(xiàn)內(nèi)存管理方法及垃圾回收的詳細步驟。

          • 第21章為第6部分,介紹Go語言可視化工具——pprof與trace。詳細論述了通過工具排查問題、觀察系統(tǒng)運行狀態(tài)的方法與實現(xiàn)原理。

          本書作者

          鄭建勛

          Golang contributor(Go語言垃圾回收模塊代碼貢獻者)、Go語言精度庫shopspring/decimal核心貢獻者。滴滴高級研發(fā)工程師。擁有豐富的分布式、高并發(fā)、大規(guī)模微服務集群的開發(fā)設計經(jīng)驗。

          微信公眾號“gopher夢工廠”作者,知名go語言原創(chuàng)博主,51CTO學堂高級講師、極客時間“每日一課”講師。有豐富的教育經(jīng)驗,想讀者之所想。相信這部系統(tǒng)且深入淺出的作品,會是讀者打怪升級的最佳輔助。



          專家力薦

          這是一本Go語言的初學者和進階學者都可以受益的書。它不僅僅介紹了Go的語言特性,還深入這些特性背后的設計考量、編譯器及語言實現(xiàn)的細節(jié)。授人以魚和授人以漁在本書里面一起得到了體現(xiàn)。更難得的是,本書并沒有粘貼大段的代碼,而是以圖文的形式將復雜的概念解釋清楚,降低了閱讀和理解的難度,使得讀者不會望“底層”和“深入”二詞而卻步。

           ——葉紹志博士  Shopee技術委員會主席、順豐速運前CTO、Google前主任工程師


           
          如果喜歡本文
          歡迎 在看留言分享至朋友圈 三連

           熱文推薦  





          ▼點擊閱讀原文,查看本書詳情~

          瀏覽 17
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  男人的天堂网2 | 久久精品国产青青草 | 青青草自拍偷拍在线视频 | AA片在线免费观看 | 亚洲自拍无码 |