掌握Go的運行時:從編譯到執行

来源:https://www.cnblogs.com/xfuture/archive/2023/09/03/17674595.html
-Advertisement-
Play Games

> 講解Go語言從編譯到執行全周期流程,每一部分都會包含豐富的技術細節和實際的代碼示例,幫助大家理解。 > 關註微信公眾號【TechLeadCloud】,分享互聯網架構、雲服務技術的全維度知識。作者擁有10+年互聯網服務架構、AI產品研發經驗、團隊管理經驗,同濟本復旦碩,復旦機器人智能實驗室成員,阿 ...


講解Go語言從編譯到執行全周期流程,每一部分都會包含豐富的技術細節和實際的代碼示例,幫助大家理解。

關註微信公眾號【TechLeadCloud】,分享互聯網架構、雲服務技術的全維度知識。作者擁有10+年互聯網服務架構、AI產品研發經驗、團隊管理經驗,同濟本復旦碩,復旦機器人智能實驗室成員,阿裡雲認證的資深架構師,項目管理專業人士,上億營收AI產品研發負責人。

file

一、Go運行編譯簡介

Go語言(也稱為Golang)自從2009年由Google發佈以來,已成為現代軟體開發中不可或缺的一部分。設計者Rob Pike, Ken Thompson和Robert Griesemer致力於解決多核處理器、網路系統和大型代碼庫所引發的現實世界編程問題。在這一節中,我們將深入探討Go語言在運行和編譯方面的核心思考點。

Go語言的目標和設計哲學

Go語言的目標是實現高性能、生產效率和軟體質量的完美平衡。為了達成這一目標,設計者在以下幾個方面作出了關鍵性的思考:

  1. 簡單性:通過減少語言特性的數量,讓語言更容易學習和使用。
  2. 高性能:既要實現近似於C/C++的執行速度,又要有像Python一樣快速的開發周期。
  3. 併發支持:原生支持併發編程,充分利用現代多核處理器。

運行時環境

Go的運行時環境是為高效執行、併發和垃圾收集等目標精心設計的。設計者在這方面特別註意了以下幾點:

  1. 輕量級線程(Goroutines):設計者考慮瞭如何有效地實現併發,而不僅僅是通過傳統的線程模型。Goroutines比操作系統線程更輕量級,能更高效地利用系統資源。

  2. 記憶體管理:Go運行時包含垃圾收集器,用於自動管理記憶體。設計者在垃圾收集演算法的選擇和實現上進行了大量的優化工作,以減少延遲並提高性能。

  3. 網路I/O:Go的運行時環境也包括了高效的網路I/O支持,以簡化網路編程,並優化性能。

編譯過程

Go語言特別註重編譯速度,以下是幾個主要的思考點:

  1. 依賴分析:Go的包管理和依賴解析機制簡單而高效,使得整個編譯過程非常迅速。

  2. 即時編譯與靜態編譯:Go編譯器支持快速的即時編譯,同時生成的是靜態鏈接的可執行文件,減少了在運行時解析和載入共用庫所需的時間和資源。

  3. 跨平臺:設計者確保Go編譯器能夠輕易地為不同的操作系統和體繫結構生成代碼。

  4. 優化:雖然Go編譯器強調編譯速度,但設計者也在生成的機器代碼的優化上投入了大量的努力。

小結

總體而言,Go語言的設計者在運行和編譯方面進行了大量深思熟慮的決策,以實現性能、簡單性和可用性的完美結合。這也是Go能迅速嶄露頭角,成為現代編程語言中的一員大將的關鍵因素之一。


二、執行環境

file
Go語言的執行環境不僅涵蓋了運行時(Runtime)系統,還包括了底層操作系統和硬體的交互。這個環境是Go高性能、高併發性能的核心。本節將從多個方面深入解析Go語言的執行環境。

操作系統與硬體層

系統調用(Syscalls)

Go語言對系統調用進行了封裝,使得程式可以在不同的操作系統(如Linux、Windows和macOS)上無縫運行。這些封裝過程會通過彙編代碼或C語言與操作系統交互。

虛擬記憶體

Go的記憶體管理與操作系統的虛擬記憶體系統緊密相連。這包括頁面大小、頁面對齊以及使用mmap或相應的系統調用進行記憶體分配。

Go運行時(Runtime)

Goroutine調度器

file
Go語言的運行時包括一個內建的Goroutine調度器。這個調度器使用M:N模型,其中M是操作系統線程,N是Goroutines。

  1. GMP模型: Go的調度模型是基於G(Goroutine)、M(Machine,即OS線程)和P(Processor,即虛擬CPU)的。P代表了可以運行Goroutine的資源。

  2. 工作竊取(Work Stealing): 為了更有效地利用多核CPU,Go的調度器採用工作竊取演算法,使得空閑的P可以“竊取”其他P的任務。

記憶體管理和垃圾收集

Go的運行時包含了一個垃圾收集器,它是併發和並行的。

  1. Tri-color標記清除(Mark and Sweep): Go使用Tri-color演算法進行垃圾回收。

  2. 寫屏障(Write Barrier): Go的GC還使用寫屏障技術,以支持併發的垃圾回收。

  3. 逃逸分析(Escape Analysis): 在編譯期間,Go進行逃逸分析,以確定哪些變數需要在堆上分配,哪些可以在棧上分配。

網路I/O

Go的網路I/O模型是基於事件驅動的。

  1. Epoll/Kqueue: 在Unix-like系統上,Go使用Epoll(Linux)或Kqueue(BSD、macOS)來實現高效的網路I/O。

  2. 非阻塞I/O: Go運行時將所有的I/O操作設置為非阻塞模式,並通過Goroutine調度器來進行管理,實現了非同步I/O的效果。

代碼示例:Go運行時調度

// 使用Goroutine進行簡單的任務調度
go func() {
    fmt.Println("Hello from Goroutine")
}()

輸出:

Hello from Goroutine

深度思考

  1. 可擴展性與微服務: Go的執行環境設計使其非常適合微服務架構。高效的Goroutine調度和網路I/O處理意味著Go可以輕易地擴展,以處理大量的併發請求。

  2. 垃圾收集與延遲敏感應用: 儘管Go的垃圾收集器是優化過的,但在極度延遲敏感的應用場景中,垃圾收集可能仍是一個需要關註的問題。

  3. 跨平臺的挑戰與機會: 雖然Go旨在成為跨平臺的編程語言,但在不同的操作系統和硬體架構上,執行性能和行為可能會有差異。

通過深入理解Go的執行環境,開發者可以更有效地利用Go的強大功能,解決實際問題。這也有助於理解Go語言如何實現其出色的性能和靈活性。


三、編譯與鏈接

file
Go語言編譯器和鏈接器都是Go語言生態系統中至關重要的組件。它們不僅保證代碼能被有效地轉換成機器指令,還確保不同的代碼模塊能被正確地組合在一起。這一節將詳細解析Go編譯與鏈接的各個方面。

Go編譯器

file

詞法、語法分析與中間表示

編譯器首先進行詞法分析和語法分析,生成抽象語法樹(AST)。接下來,AST會被轉化成更加簡潔的中間表示(IR)。

類型檢查

Go編譯器在編譯期進行嚴格的類型檢查,包括但不限於介面實現、空值使用以及變數初始化等。

優化

編譯器會在IR上進行各種優化,包括常量摺疊、死代碼消除、迴圈展開等。

代碼生成

編譯器最後會將優化過的IR轉換為目標平臺的機器代碼。

Go鏈接器

符號解析

Go鏈接器首先解析各個代碼模塊(通常是.o.a文件)中的符號表,確定哪些符號是外部的,哪些是內部的。

依賴解析與包管理

Go使用一個特定的包管理策略,允許靜態和動態鏈接。Go模塊(Go Modules)現為官方推薦的依賴管理工具。

最終代碼生成

鏈接器最後將所有的代碼模塊和依賴庫組合成一個單一的可執行文件。

代碼示例:編譯與鏈接

# 編譯Go代碼
go build main.go

# 編譯並生成靜態鏈接的可執行文件
CGO_ENABLED=0 go build -o static_main main.go

深度思考

  1. 編譯速度與優化: Go強調快速編譯,但這是否限制了編譯器進行更深度的優化?這是一個權衡。

  2. 包管理與版本控制: Go Modules為依賴管理提供了一種現代解決方案,但在大型、複雜的代碼庫中,版本管理可能變得複雜。

  3. 靜態與動態鏈接: Go通常生成靜態鏈接的可執行文件,這大大簡化了部署,但也帶來了可執行文件體積較大、不易進行動態更新等問題。

  4. 跨平臺編譯: Go支持交叉編譯,這是其強大的一個方面,但也可能帶來目標平臺特定的問題,例如系統調用和硬體優化。

通過瞭解Go的編譯和鏈接過程,開發者不僅能更有效地解決問題,還能更深入地理解語言的底層原理和設計思想,從而編寫更高效、更可維護的代碼。

四、執行模型

file
Go語言的執行模型是指在程式運行時,各個代碼塊是如何被執行的。從程式開始執行到結束,涉及到的函數調用、棧幀管理以及異常處理等方面,都構成了Go的執行模型。本節將深入探討Go語言的執行模型。

主函數(main function)

在Go程式中,執行起始於main函數。當程式運行時,Go運行時會調用main函數,作為程式的入口點。從main函數開始,程式的執行路徑會在各個函數之間跳轉,直到main函數返回或發生異常。

初始化過程

Go的初始化過程包括:

  1. 導入包:Go會從main函數開始逐級導入所需的包,確保依賴被滿足。

  2. 初始化包級變數:每個包中的全局變數會被初始化,如果有多個包,會按照依賴順序依次初始化。

  3. 執行init函數:每個包中的init函數會按照導入順序執行,用於完成一些初始化工作。

函數調用與返回

Go語言使用棧來管理函數的調用與返回。當一個函數被調用時,會在棧上分配一個新的棧幀。棧幀中存儲了函數的參數、局部變數以及函數調用的返回地址。當函數執行完成時,棧幀會被彈出,控制權回到調用函數。

延遲(defer)函數

Go的執行模型中有一個重要特性是延遲函數。通過defer關鍵字,可以將函數推遲到所在函數結束時執行。這在資源釋放、錯誤處理等方面非常有用。

遞歸與尾調用優化

Go支持遞歸函數調用。尾調用優化(Tail Call Optimization)雖然不是Go的一部分,但瞭解遞歸和尾調用優化有助於理解執行模型中的一些細節。

深度思考

  1. 函數調用開銷與棧空間: 雖然Go的函數調用開銷相對較低,但遞歸過程中可能會耗盡棧空間。如何在保持遞歸思維的同時,避免棧溢出,是需要註意的問題。

  2. 延遲函數與資源管理: 延遲函數的使用是一種優雅的資源管理方式,但在處理需要立即釋放資源的情況下,可能需要特殊的註意。

  3. 初始化與啟動性能: 對於一些小型應用,Go的初始化和啟動可能會顯得稍微有些耗時。瞭解這些過程有助於設計更快速響應的應用。

通過深入理解Go的執行模型,開發者可以更好地利用函數、調用和延遲等特性,以及優化遞歸、減少延遲函數的調用等方法,編寫高效、可讀性強的Go代碼。

個人微信公眾號:【TechLeadCloud】分享AI與雲服務研發的全維度知識,談談我作為TechLead對技術的獨特洞察。
TeahLead KrisChang,10+年的互聯網和人工智慧從業經驗,10年+技術和業務團隊管理經驗,同濟軟體工程本科,復旦工程管理碩士,阿裡雲認證雲服務資深架構師,上億營收AI產品業務負責人。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ### 歡迎訪問我的GitHub > 這裡分類和彙總了欣宸的全部原創(含配套源碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 本篇概覽 - 本文是《LeetCode952三部曲》系 ...
  • # 實驗目的 - 熟悉並掌握 MIPS 電腦中寄存器堆的原理和設計方法 - 理解源操作數/目的操作數的概念 # 實驗環境 * Vivado 集成開發環境 # MIPS寄存器 ![](https://pic.imgdb.cn/item/64f40fab661c6c8e5400bf9a.jpg) * ...
  • acwing學習筆記,記錄容易忘記的知識點和難題。數組實現單鏈表、雙鏈表、棧、單調棧、隊列、單調隊列、KMP、字典樹 Trie、並查集、數組實現堆、哈希表(拉鏈法、開放定址法、字元串首碼哈希法)、STL常用容器 ...
  • ## 1、使用互斥量 在C++中,我們通過構造`std::mutex`的實例來創建互斥量,調用成員函數`lock()`對其加鎖,調用`unlock()`解鎖。但通常更推薦的做法是使用標準庫提供的類模板`std::lock_guard`,它針對互斥量實現了RAII手法:在構造時給互斥量加鎖,析構時解鎖 ...
  • ## 預編譯頭文件 在 Visual Studio 中創建新項目時,會在項目中添加一個名為 pch.h 的“預編譯標頭文件”。 (在 Visual Studio 2017 及更高版本中,該文件名為 stdafx.h)此文件的目的是加快生成過程。 應在此處包含任何穩定的標頭文件,例如標準庫標頭(如 ) ...
  • 集合是一種無序、可變的數據結構,它也是一種變數類型,集合用於存儲唯一的元素。集合中的元素不能重覆,並且沒有固定的順序。在Python 提供了內置的 `set` 類型來表示集合,所以關鍵字`set`就是集合的意思。 你可以使用大括弧 `{}` 或者 `set()` 函數來創建一個集合。 ```pyth ...
  • `Matplotlib`的**坐標軸**是用於在繪圖中表示數據的位置的工具。 坐標軸是圖像中的水平和垂直線,它們通常表示為 x 軸和 y 軸。坐標軸的作用是幫助觀察者瞭解圖像中數據的位置和大小,通常標有數字或標簽,以指示特定的值在圖像中的位置。 # 1. 坐標軸範圍 `Matplotlib`繪製圖形 ...
  • 本文主要介紹 RocketMQ 的安裝部署,文中所使用到的軟體版本:RocketMQ 5.1.3、CentOS 7.9.2009。 1、RocketMQ 部署模型 1.1、部署模型說明 Apache RocketMQ 部署架構上主要分為四部分: A、生產者 Producer 發佈消息的角色。Prod ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...