# 6.12 非均勻訪存下的調度模型
## 6.12.1 調度器架構的演變
Go 的運行時調度器只經歷了兩個主要版本的迭代。Go 語言誕生之初的調度器,和我們現在所看到的從 Go 1.1 起引入的工作竊取調度器。
### 單線程版調度器
最早期(Go 1 之前)的 Go 調度器甚至不能良好的支持多線程 \[Cox, 2008\],即默認的最大 M 數為 1。 這個版本的調度器負責將準備運行的 G 與等待工作的調度程序 M 相匹配。如果有準備好的 G 且沒有等待的 M,則會在新的 OS 線程中啟動一個新的 m, 這樣所有準備好的(有限多個)G 可以同時運行。并且,這時的 M 無法退出。
原因在于最早先的 Go 只適當的支持了 Linux,甚至連目標支持的 OS X (當時還沒有更名為 macOS)也尚未實現。 其中一個主要的問題就在調度器鎖的處理并不完善、垃圾回收的支持也不夠完整。
### 多線程版調度器
隨后的一年時間中,調度器得到了完善的改進,能夠正式的支持多個系統線程的版本 \[Cox, 2009\]。 但這時仍然需要用戶態代碼通過 $GOMAXPROCS 或 runtime.GOMAXPROCS() 調用來調整最大核數。 而`m`不能退出的問題仍然沒有得到改進。
### 工作竊取調度器
隨著 Go 1.1 的出現,Go 的運行時調度器得到了質的飛越,調度器正式引入 M 的本地資源 P \[Vyukov, 2013a\], 大幅降低了任務調度時對全局鎖的競爭,提出了沿用至今的 MPG 工作竊取式調度器設計。 我們已經在前面的使用了大量篇幅介紹這一調度器的設計,這里便不再贅述了。
## 6.12.2 改進展望:非均勻訪存感知的調度器
目前的調度器設計總是假設 M 到 P 的訪問速度是一樣的,即不同的 CPU 核心訪問多級緩存、內存的速度一致。 但真實情況是,在 NUMA(non-uniform memory access,非均勻訪存)架構下,CPU 僅在 局部訪問自身 NUMA 節點內的內存時才能獲得一致的訪問速度。更一般地說,這種基于 NUMA 架構的處理器是也是一個分布式的系統。
**圖 1:NUMA 架構**
針對這一點,Go 官方已經提出了具體的調度器設計 \[Vyukov, 2014\],但由于工作量巨大,甚至沒有提上日程。
TODO: 討論設計的優劣
## 小結
Go 語言用戶態代碼的調度核心在未來的十年里只進行了兩次改進,足見其設計功力, 但隨著 Go 語言的大規模應用,以及越來越多的在多核機器上使用調度器的性能問題也會逐漸暴露出來, 讓我們對未來下一個大版本的改進拭目以待。
- 第一部分 :基礎篇
- 第1章 Go語言的前世今生
- 1.2 Go語言綜述
- 1.3 順序進程通訊
- 1.4 Plan9匯編語言
- 第2章 程序生命周期
- 2.1 從go命令談起
- 2.2 Go程序編譯流程
- 2.3 Go 程序啟動引導
- 2.4 主Goroutine的生與死
- 第3 章 語言核心
- 3.1 數組.切片與字符串
- 3.2 散列表
- 3.3 函數調用
- 3.4 延遲語句
- 3.5 恐慌與恢復內建函數
- 3.6 通信原語
- 3.7 接口
- 3.8 運行時類型系統
- 3.9 類型別名
- 3.10 進一步閱讀的參考文獻
- 第4章 錯誤
- 4.1 問題的演化
- 4.2 錯誤值檢查
- 4.3 錯誤格式與上下文
- 4.4 錯誤語義
- 4.5 錯誤處理的未來
- 4.6 進一步閱讀的參考文獻
- 第5章 同步模式
- 5.1 共享內存式同步模式
- 5.2 互斥鎖
- 5.3 原子操作
- 5.4 條件變量
- 5.5 同步組
- 5.6 緩存池
- 5.7 并發安全散列表
- 5.8 上下文
- 5.9 內存一致模型
- 5.10 進一步閱讀的文獻參考
- 第二部分 運行時篇
- 第6章 并發調度
- 6.1 隨機調度的基本概念
- 6.2 工作竊取式調度
- 6.3 MPG模型與并發調度單
- 6.4 調度循環
- 6.5 線程管理
- 6.6 信號處理機制
- 6.7 執行棧管理
- 6.8 協作與搶占
- 6.9 系統監控
- 6.10 網絡輪詢器
- 6.11 計時器
- 6.12 非均勻訪存下的調度模型
- 6.13 進一步閱讀的參考文獻
- 第7章 內存分配
- 7.1 設計原則
- 7.2 組件
- 7.3 初始化
- 7.4 大對象分配
- 7.5 小對象分配
- 7.6 微對象分配
- 7.7 頁分配器
- 7.8 內存統計
- 第8章 垃圾回收
- 8.1 垃圾回收的基本想法
- 8.2 寫屏幕技術
- 8.3 調步模型與強弱觸發邊界
- 8.4 掃描標記與標記輔助
- 8.5 免清掃式位圖技術
- 8.6 前進保障與終止檢測
- 8.7 安全點分析
- 8.8 分代假設與代際回收
- 8.9 請求假設與實務制導回收
- 8.10 終結器
- 8.11 過去,現在與未來
- 8.12 垃圾回收統一理論
- 8.13 進一步閱讀的參考文獻
- 第三部分 工具鏈篇
- 第9章 代碼分析
- 9.1 死鎖檢測
- 9.2 競爭檢測
- 9.3 性能追蹤
- 9.4 代碼測試
- 9.5 基準測試
- 9.6 運行時統計量
- 9.7 語言服務協議
- 第10章 依賴管理
- 10.1 依賴管理的難點
- 10.2 語義化版本管理
- 10.3 最小版本選擇算法
- 10.4 Vgo 與dep之爭
- 第12章 泛型
- 12.1 泛型設計的演進
- 12.2 基于合約的泛型
- 12.3 類型檢查技術
- 12.4 泛型的未來
- 12.5 進一步閱讀的的參考文獻
- 第13章 編譯技術
- 13.1 詞法與文法
- 13.2 中間表示
- 13.3 優化器
- 13.4 指針檢查器
- 13.5 逃逸分析
- 13.6 自舉
- 13.7 鏈接器
- 13.8 匯編器
- 13.9 調用規約
- 13.10 cgo與系統調用
- 結束語: Go去向何方?