[TOC]
# 簡介
go為并發編程而內置上層api是基于csp(communicating sequential process, 順序通信進程)模型.這就意味顯示鎖是可以避免的.因為go通過安全的通道發送和接受數據以實現同步
goroutine是go并行設計的核心,他比線程更小,十幾個協程體現在底層就是5-6個線程,go幫你實現了這些協程之間的內存共享.執行協程只需極少的棧內存(大概是4-5kb),當然會根據相應的數據伸縮
~~~
return //返回當前函數
runtime.Goexit() //結束當前go程序
os.Exit(1) //當前進程結束,狀態碼,正常是0
~~~

# 關于線程
我們每運行的一個程序都會創建一個進程,每個進程都有一個初始線程,而后初始線程可以創建更多線程,每個線程互相獨立地運行。線程因為其輕量和易用性在并發編程中被大量的使用。而 goroutine 就是基于線程的。線程的實現模型主要有3種:用戶級線程模型、內核級線程模型和兩級線程模型(或者叫做混合型線程模型)。他們之間的區別就是用戶線程和系統最小調度單元內核調度實體(KSE,Kernal Scheduling Entity)的對應關系不同。
# 用戶級線程模型
用戶線程與內核線程KSE是多對一的映射模型,多個用戶線程一般都是從屬于單個進程,并且用戶線程的調度都是用戶程序的線程庫完成的,不需要操作系統調度。一個進程所創建的所有線程都和同一個KSE綁定,操作系統調度只知道進程對線程無感知,這種模型實現的線程調度是用戶層實現的不需要操作系統內核調度所以是輕量級的。但是這種模型最根本缺點就是并不能實現真正意義上的并發,因為單個進程的所有線程都是綁定在同一個KSE,各個用戶線程交替執行,如果某一個用戶線程阻塞了,那么整個進程就會阻塞。
# 內核級線程模型
用戶線程與內核線程KSE是一對一(1:1)的映射模型,也就是每一個用戶線程綁定一個真實的內核線程,那么線程調度就完全依賴于操作系統的內核調度,java語言等就是這種模式,這種模式雖然實現了真正的并行但是線程調度代價很大,嚴重影響系統性能。
# 兩級線程模型
兩級線程模型綜合了上面兩種模式優點,在此模型中用戶線程和內核線程KSE是多對多的關系,與內核級線程模型不同的是兩級線程模型中的進程可以和多個KSE綁定,而進程中的線程并不會和某一個KSE綁定,而會動態調整,當進程中的某一個線程阻塞了某一個KSE,那么進程中其余的線程會去綁定到其他的KSE。所以兩級線程模型即不像用戶線程模型完全靠用戶調度也不像內核級線程模型完全依賴系統調度,而是一個中間態的模型。而 goroutine 就是調度器就是采用這種模型。
# G-P-M模型
golang調度系統中有3個比較重要的概念那就是G、P、M:
* G: goroutine,是 golang 調度系統中封裝出來的調度單元。
* P:Processor,是 golang 調度系統中封裝出的“CPU“,其提供了執行環境、內存分配狀態和任務隊列等。P的數量決定了 golang 系統中最大并行 goroutine 的數量。
* M 用戶空間線程,同時對應一個內核線程。
# G、P、M、KSE關系

根據圖中2個概念需要說明:
1. Global隊列,隊列里是待執行的G.
2. P,每個P包含一個待執行G隊列,叫做本地運行隊列,隊列中 G 有數量限制,最多包含256個。
當我們通過*go*關鍵字創建一個新的 goroutine 的時候,他會優先被放入到P的本地運行隊列,如果P運行隊列已滿,就會放入到Global 隊列中。每個M會綁定到一個 KSE ,并隨機選擇一個 P ,然后 M 會啟動一個 OS 線程循環從綁定的P里獲得 goroutine 并執行。直到P中G執行完畢,然后P會嘗試從 Global 隊列里獲得G來執行,如果 Global 隊列為空那么P會隨機挑選另外一個P,從它的隊列里拿來一般的G到自己的隊列中執行。
**M、P的關聯**
P的數量默認是CPU的數量或者 runtime.GOMAXPROCS() 來決定,在確定了P的數量后,go 運行時系統會創建相應數量的P。當P中本地運行隊列不為空的時候,P會去綁定一個M,如果沒有多余的M的話,那么系統回去創建一個M,go 系統會設置M最大數量限制,最大為10000。M和P沒有絕對的關系,M會隨機選擇一個P綁定,當M阻塞的時候而P的本地運行隊列不為空那么P就會去創建或者切換到一個新的M,所以即使P的默認數量是1也會創建出多個M
- 基礎
- 簡介
- 主要特征
- 變量和常量
- 編碼轉換
- 數組
- byte與rune
- big
- sort接口
- 和mysql類型對應
- 函數
- 閉包
- 工作區
- 復合類型
- 指針
- 切片
- map
- 結構體
- sync.Map
- 隨機數
- 面向對象
- 匿名組合
- 方法
- 接口
- 權限
- 類型查詢
- 異常處理
- error
- panic
- recover
- 自定義錯誤
- 字符串處理
- 正則表達式
- json
- 文件操作
- os
- 文件讀寫
- 目錄
- bufio
- ioutil
- gob
- 棧幀的內存布局
- shell
- 時間處理
- time詳情
- time使用
- new和make的區別
- container
- list
- heap
- ring
- 測試
- 單元測試
- Mock依賴
- delve
- 命令
- TestMain
- path和filepath包
- log日志
- 反射
- 詳解
- plugin包
- 信號
- goto
- 協程
- 簡介
- 創建
- 協程退出
- runtime
- channel
- select
- 死鎖
- 互斥鎖
- 讀寫鎖
- 條件變量
- 嵌套
- 計算單個協程占用內存
- 執行規則
- 原子操作
- WaitGroup
- 定時器
- 對象池
- sync.once
- 網絡編程
- 分層模型
- socket
- tcp
- udp
- 服務端
- 客戶端
- 并發服務器
- Http
- 簡介
- http服務器
- http客戶端
- 爬蟲
- 平滑重啟
- context
- httptest
- 優雅中止
- web服務平滑重啟
- beego
- 安裝
- 路由器
- orm
- 單表增刪改查
- 多級表
- orm使用
- 高級查詢
- 關系查詢
- SQL查詢
- 元數據二次定義
- 控制器
- 參數解析
- 過濾器
- 數據輸出
- 表單數據驗證
- 錯誤處理
- 日志
- 模塊
- cache
- task
- 調試模塊
- config
- 部署
- 一些包
- gjson
- goredis
- collection
- sjson
- redigo
- aliyunoss
- 密碼
- 對稱加密
- 非對稱加密
- 單向散列函數
- 消息認證
- 數字簽名
- mysql優化
- 常見錯誤
- go run的錯誤
- 新手常見錯誤
- 中級錯誤
- 高級錯誤
- 常用工具
- 協程-泄露
- go env
- gometalinter代碼檢查
- go build
- go clean
- go test
- 包管理器
- go mod
- gopm
- go fmt
- pprof
- 提高編譯
- go get
- 代理
- 其他的知識
- go內存對齊
- 細節總結
- nginx路由匹配
- 一些博客
- redis為什么快
- cpu高速緩存
- 常用命令
- Go 永久阻塞的方法
- 常用技巧
- 密碼加密解密
- for 循環迭代變量
- 備注
- 垃圾回收
- 協程和纖程
- tar-gz
- 紅包算法
- 解決golang.org/x 下載失敗
- 逃逸分析
- docker
- 鏡像
- 容器
- 數據卷
- 網絡管理
- 網絡模式
- dockerfile
- docker-composer
- 微服務
- protoBuf
- GRPC
- tls
- consul
- micro
- crontab
- shell調用
- gorhill/cronexpr
- raft
- go操作etcd
- mongodb