go基礎系列~併發協程

零 基礎
協程 一種比線程更加輕量級的存在。正如一個進程可以擁有多個線程一樣,一個線程也可以擁有多個協程,協程的切換和創建完全是用戶決定的

很多時候 Mutex 並不是單獨使用的,而是嵌套在 Struct 中使用,作爲結構體的一部分,如果嵌入的 struct 有多個字段,我們一般會把 Mutex 放在要控制的字段上面,然後使用空格把字段分隔開來。

甚至可以把獲取鎖、釋放鎖、計數加一的邏輯封裝成一個方法。

type Person struct {
mux sync.Mutex|WaitGroup
}
func (p *Peron) test(){
    def p.mux.UnLock()
p.mux.Lock()
}
func main() {
p1:=Person{mux: sync.Mutex{}} #初始化賦值

}

看到這裏我們就能發現, 當 struct 嵌套了 Mutex, 如果以值傳遞的方式使用時, 有可能造成程序死鎖, 有可能需要互斥的變量並不能達到互斥.

所以不管是單獨使用 不能複製 類型的變量, 還是嵌套在 struct 裏面都不能值傳遞的方式使用


goroutine相對於線程:
1.Goroutine所需要的內存通常只有2kb,而線程則需要1Mb,內存消耗更少
2.由於線程創建時需要向操作系統申請資源,並且在銷燬時將資源歸還,因此它的創建和銷燬的開銷比較大。相比之下,goroutine的創建和銷燬是由go語言在運行時自己管理的,因此開銷更低。
3.切換開銷更小線程的調度方式是搶佔式的,如果一個線程的執行時間超過了分配給它的時間片,就會被其它可執行的線程搶佔;而goroutine的調度是協同式的,它不會直接地與操作系統內核打交道


一  Mutex 互斥鎖-Mutex是結構體
在同一時間段內有且只有一個goroutine持有鎖,保證了在這段時間內只有一個goroutine訪問共享資源,其他申請鎖的goroutine將會被阻塞直到釋放
常用函數 Lock() Unlock()
在Lock()和Unlock()之間的代碼部分是臨界區
var lock sync.Mutex //定義
go func(){
defer lock.Unlock()
lock.Lock()
//下面整套處理邏輯都是臨界區
fmt.Prinln(time.now())
}

二   RWMutex 讀寫鎖
R(Lock|UnLock) W(Lock|Unlock)
1 在同一個時間段內只能有一個goroutine獲取到寫鎖
2 在同一個時間段內可以有多個goroutine獲取到讀鎖
3 在同一時間段在只能存在寫鎖或者讀鎖(讀鎖和寫鎖互斥)
三   WaitGroup 併發等待組
var gp sync.WaitGroup
for i:=0;i<=5;i++{
gp.Add(1)
go func(i int) {
defer gp.Done()
fmt.Println("加鎖",i)
time.Sleep(3)
fmt.Println("釋放鎖",i)
}(i)

}
fmt.Println("鎖等待")
gp.Wait()
1 使用WaitGroup的goroutine會等待預設好數量的goroutine都提交執行結束後,纔會繼續往下執行代碼
2 在goroutine調用WaitGroup之前我們需要保證WaitGroup中等待數據大於1
3 保證WaitGroup.Done()執行的次數與WaitGroup.Add()相同,過少會導致等待goroutine死鎖,過多會導致painic

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章