## 動態棧
原生系統線程的棧是確定大小的,都是2M.但是goroutine的棧一般只有2k,比原生線程要小的多.得益于此,可以同時啟動成千上萬個goroutine.
但是goroutine的大小不是固定的,小至2k,大到1G.
## 原生線程調度
OS線程會被操作系統內核調度。每幾毫秒,一個硬件計時器會中斷處理器,這會調用一個叫作scheduler的內核函數。這個函數會掛起當前執行的線程并將它的寄存器內容保存到內存中,檢查線程列表并決定下一次哪個線程可以被運行,并從內存中恢復該線程的寄存器信息,然后恢復執行該線程的現場并開始執行線程。因為操作系統線程是被內核所調度,所以從一個線程向另一個“移動”需要完整的上下文切換,也就是說,保存一個用戶線程的狀態到內存,恢復另一個線程的到寄存器,然后更新調度器的數據結構。這幾步操作很慢,因為其局部性很差需要幾次內存訪問,并且會增加運行的cpu周期。
## goroutine調度
Go的運行時包含了其自己的調度器,這個調度器使用了一些技術手段,比如m:n調度,因為其會在n個操作系統線程上多工(調度)m個goroutine。Go調度器的工作和內核的調度是相似的,但是這個調度器只關注單獨的Go程序中的goroutine(譯注:按程序獨立)。
和操作系統的線程調度不同的是,Go調度器并不是用一個硬件定時器,而是被Go語言“建筑”本身進行調度的。例如當一個goroutine調用了time.Sleep,或者被channel調用或者mutex操作阻塞時,調度器會使其進入休眠并開始執行另一個goroutine,直到時機到了再去喚醒第一個goroutine。因為這種調度方式不需要進入內核的上下文,所以重新調度一個goroutine比調度一個線程代價要低得多。
## GOMAXPROCS
Go的調度器使用了一個叫做GOMAXPROCS的變量來決定會有多少個操作系統的線程同時執行Go的代碼。其默認的值是運行機器上的CPU的核心數,所以在一個有8個核心的機器上時,調度器一次會在8個OS線程上去調度GO代碼。(GOMAXPROCS是前面說的m:n調度中的n)。在休眠中的或者在通信中被阻塞的goroutine是不需要一個對應的線程來做調度的。在I/O中或系統調用中或調用非Go語言函數時,是需要一個對應的操作系統線程的,但是GOMAXPROCS并不需要將這幾種情況計算在內。
**上面的意思就是,可以允許當前程序使用多少個原生的系統線程.因為協程是跑在OS線程上面的,當只分配了一個OS線程的時候,同時能運行的攜程數量也就只有1個了.**那么此時只能達到并發,而不能達到并行.
## goroutine沒有ID號
原生OS線程是有ID號的,所以可以根據當前線程的ID號,來做一些針對此線程的本地存儲.
但是協程是沒有ID號的,這樣設計的目的就是防止,本地存儲被濫用.
- 基本語法
- 申明變量
- 常量
- 數據類型
- 強制類型轉換
- 獲取命令行參數
- 指針
- 概述
- new函數
- 函數
- 概述
- 不定參數類型
- 有返回值
- 函數類型
- 回調函數
- 匿名函數和閉包
- 延遲調用defer
- 工程管理
- 工作區
- src,pkg和bin目錄
- 復合類型
- 概述
- 數組
- 概述
- 聲明并初始化
- 拷貝傳值
- slice
- 概述
- 創建切片
- 切片截取
- 切片和底層數組的關系
- slice常用方法
- 切片做函數參數
- map
- 概述
- map操作
- 結構體
- 概述
- 結構體初始化
- 結構體比較
- 結構體作為函數參數
- 結構體前加&
- 面向對象
- 概述
- 匿名組合
- 方法
- 值語義和引用語義
- 方法集
- 方法的繼承
- 方法重寫
- 方法值
- 接口
- 接口定義和實現
- 多態的表現
- 接口繼承
- 接口轉換
- 空接口
- 類型斷言
- 異常處理
- error接口
- panic
- recover
- 文本文件處理
- 字符串操作
- 正則表達式
- json處理
- 文件操作
- 標準設備文件操作
- 并發編程
- 概述
- 并發和并行
- go語言并發優勢
- goroutine
- goroutine概述
- 創建goroutine
- 主協程先退出
- runtime包
- Gosched
- Goexit
- GOMAXPROCE
- channel
- 多資源競爭
- channel類型
- 無緩沖channel
- 有緩沖channel
- 關閉channel
- 單向channel
- 單向channel特性
- 定時器
- Timer
- Ticker
- select
- select作用
- 超時
- sync
- 競爭狀態
- 網絡編程
- 網絡概述
- 網絡協議
- 分層模型
- 網絡分層架構
- 層與協議
- 每層協議的功能
- 鏈路層
- 網絡層
- 傳輸層
- 應用層
- socket編程
- 組合和繼承
- 注意事項
- 細節
- go語言實現隊列
- google工程師golang
- 基礎語法
- 內建容器
- 面向"對象"
- 依賴管理
- 面向接口
- 函數式編程
- 錯誤處理和資源管理
- 測試與性能調優
- goroutine
- channel
- golang問題集
- 斷言和類型轉換
- Go語言圣經
- 入門
- 程序結構
- 命名
- 聲明
- 變量
- 賦值
- 類型
- 包和文件
- 作用域
- 基礎數據類型
- 整數
- 浮點數
- 復數
- 布爾型
- 字符串
- 常量
- 復合數據類型
- 數組
- slice
- map
- 結構體
- json
- 文本和HTML模板
- 函數
- 函數聲明
- 錯誤
- 函數值
- 匿名函數
- defer
- panic
- recover
- 方法
- 方法聲明
- 指針對象的方法
- 封裝
- 接口
- 說明
- 接口是合約
- 實現接口的條件
- 接口值
- 類型斷言
- 通過類型斷言詢問行為
- 類型開關
- Goroutines和Channels
- 協程
- channels
- 無緩沖channel
- 串聯的channel
- 有緩沖channel
- 并發的循環
- select多路復用
- 并發的退出
- 并發問題的自我思考
- 基于共享變量的并發
- 競爭條件
- 互斥鎖
- 讀寫鎖
- 內存同步
- sync.Once
- 協程和線程
- 包和工具
- 測試
- 反射
- 什么是反射
- 為什么需要反射
- reflect.Type和reflect.Value
- 通過reflect.Value修改值
- 底層編程