Go語言的併發是是指goroutine運行時是相互獨立的,能讓某個函數獨立於其他函數運行。
併發不是並行。並行是讓不同的代碼片段同時在不同的物理處理器上執行。並行的關鍵是同時做很多事情,而併發是指同時管理很多事情,這些事情可能只做了一半就被暫停去做別的事情了。
Go的併發同步模型來自通信順序進程(Communicating Sequential Processes,CSP)的範型。CSP是一種消息傳遞模型,通過在goroutine之間傳遞數據。而不需要對數據進行加鎖來實現同步訪問。
通道(channel)用於goroutine之間同步和傳遞數據的數據類型。
goroutinue本質上是協程,但有兩點不同:
- goroutinue可實現並行;多個協程可在多個處理器同時跑。而協程同一時刻只能在一個處理器跑。
- goroutinue之間的通信是通過channel(消息隊列);而協程的通信是通過yield和resume()操作。
---------------------------------
當一個正在運行的goroutine需要執行一個系統調用,如打開一個文件,線程會和goroutine從邏輯處理器上分離,該線程會繼續阻塞,等待系統調用的返回。與此同時,調度器會創建一個新線程,並將其綁定在邏輯處理器上。
之後,調度器會從本地運行隊列裏選擇另一個 goroutine 來運行。一旦被阻塞的系統調用執行完成並返回,對應的 goroutine 會放回到本地運行隊列,而之前的線程會保存好,以便之後可以繼續使用。
WaitGroup是計數信號量,可以用來維護運行的goroutine。
//wg用來等待程序完成
//計數加2,表示等待兩個goroutine
var wg sync.WaitGroup
wg.Add(2)
修改邏輯處理器數量
包 runtime 提供了修改 Go 語言運行時配置參數的能力。
runtime.GOMAXPROCS(runtime.NumCPU())
通道
通過使用管道發送和接收需要共享的資源,在goroutine之間做同步。
聲明通道時,需要指定將要被共享的數據的類型。可共享內置類型、命名類型、結構類型、引用類型或指針。
使用make創建管道,
//無緩衝的整形管道
unbuffered := make(chan int)
//無緩衝的字符串通道
buffered := make(chan string, 10)
make的第一個參數需要是關鍵字chan,之後跟着允許通道交換的數據類型。
向通道發送值或指針需要用到<-操作符。
無緩衝的通道(unbuffered channel):指在接收前沒有能力保存任何值。要求發送goroutine和接收goroutine同時準備好,才能進行發送和接收操作。
如果兩個foroutine同時沒有準備好,通道會導致先執行發送或接收操作的goroutine阻塞。
有緩衝的通道(buffered channel):是一種在被接收前能存儲一個或者多個值的通道。
不強制要求 goroutine 之間必須同時完成發送和接收。
只有在通道中沒有要接收的值時,接收動作纔會阻塞。
無緩衝的通道保證進行發送和接收的 goroutine 會在同一時間進行數據交換;有緩衝的通道沒有這種保證。