CSP 是 Communicating Sequential Process 的簡稱,中文可以叫做通訊順序程式,是一種併發程式設計模型,最初於Tony Hoare的1977年的論文中被描述,影響了許多程式語言的設計。
golang CSP模型
golang語言並沒有完全實現了CSP模型的所有理論,僅僅是借用了 process和channel這兩個概念。process是在golang語言上的表現就是 goroutine, 是實際併發執行的實體,每個實體之間是通過channel通訊來實現資料共享。
最經典的資料通訊共享理論
以通訊的方式來共享記憶體
Do not communicate by sharing memory; instead, share memory by communicating
不要以共享記憶體的方式來通訊,相反,要通過通訊來共享記憶體。
這是golang實現高併發的基礎通訊理論。
在golang語言上面,就是通過channel實現多個goroutine的資料通訊。
sync.WaitGroup使用
如果需要讓多個goroutine都執行完成,就是用使用time.sleep,延遲幾秒保證每個goroutine都能執行到。
func testPrint(i int) {
fmt.Println(i)
}
func main() {
for i:=0;i<5;i++ {
go testPrint(i)
}
time.Sleep(time.Second)
}
但是在生產專案裡面就沒法這麼寫了,延遲1S有可能所有goroutine沒執行完成,延遲1000S可能1毫秒就執行完了,其他999S都是等待,延長了程式執行時間。
所以就有sync.WaitGroup
func testPrint(wg *sync.WaitGroup, i int) {
fmt.Println(i)
wg.Done()
}
func main() {
var wg = new(sync.WaitGroup)
for i:=0;i<5;i++ {
wg.Add(1)
go testPrint(wg,i)
}
wg.Wait()
}
WaitGroup比較容易理解,其實就是一個內部計數器,在執行goroutine行為之前執行 wg.Add(1),給計數器+1,執行完之後,執行wg.Done(),表示這個goroutine執行完成,計數器內部-1,wg.Wait()會阻塞程式碼的執行,等待所有的新增進WaitGroup的goroutine全部執行完畢(計數器減為0),再退出程式。
非常完美的解決了等待所有goroutine執行完畢的需要。
sync.Mutex
sync.Mutex,互斥鎖排它鎖。
我們需要維護一個變數,保證每個goroutine都能成功的修改它,如果沒有互斥鎖可能就是下面的程式碼
func testPrint(wg *sync.WaitGroup, i int) {
count++
fmt.Println(i)
wg.Done()
}
var count int
func main() {
count = 0
var wg = new(sync.WaitGroup)
for i:=0;i<500;i++ {
wg.Add(1)
go testPrint(wg,i)
}
wg.Wait()
fmt.Printf("count:%d",count)
}
預期應該是特定的值,500,其實經常性的不是500.就是因為多個goroutine同時去修改count值了,加上互斥鎖試一下。
func testPrint(wg *sync.WaitGroup, i int) {
defer func() {
mu.Unlock()
}()
mu.Lock()
count++
fmt.Println(i)
wg.Done()
}
var count int
var mu *sync.Mutex
func main() {
count = 0
mu = new(sync.Mutex)
var wg = new(sync.WaitGroup)
for i:=0;i<500;i++ {
wg.Add(1)
go testPrint(wg,i)
}
wg.Wait()
fmt.Printf("count:%d",count)
}
結果是定值500,跟預想的一致。