Go語言特色編程
1.併發編程
1.1 sync.WaitGroup
類似於信號量
Add(num) 加 num;
Done() 減一;
Wait() 阻塞,一直到減到0時爲止
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(10)
for i :=0;i<10;i++ {
// 執行匿名函數,協程
go func(num int){
fmt.Println("I am ",num,"goroutine!")
wg.Done()
}(i)
}
wg.Wait()
fmp.Println("----- over ------")
}
1.2 互斥鎖 與 讀寫鎖
互斥鎖
var mutex sync.Mutex
mutex.Lock() //上鎖 , 解鎖也可以使用defer mutex.Unlock()
mutex.Unlock() // 解鎖
讀寫鎖
mutex sync.RWMutex
正常鎖
mutex.Lock()
mutex.Unlock()
讀鎖
mutex.RLock()
mutex.RUnlock()
教程
https://blog.csdn.net/sunt2018/article/details/105608184
1.3 控制代碼只在go協程中運行一次
sync.Once -> Do( 代碼或函數)
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var once sync.Once
var count int = 1
wg.Add(100)
for i := 0; i<100 ;i++ {
go func() {
once.Do(func() {
fmt.Println("add...count")
count += 1
})
wg.Done() // 減去1的操作
}()
}
wg.Wait() // 阻塞等待
fmt.Println(count)
}
1.4 Cond 條件變量實現生產者消費者模型
例子是 一個廚師(生產者),多個顧客(消費者)
廚師不停的生成,顧客不停的吃
有一個容量爲5的桌子,廚師將生產出來的東西放到桌子上每次+1,消費者吃每次-1
臨界區: 桌子的容量是5,食物的上限是5個,超過廚師不能再放食物,下限是0個,超過顧客沒有東西吃
是用cond條件變量 信號量,
當食物爲5,廚師cond.Wait()等待,顧客吃掉一個後,cond.Signal()喚醒廚子去做飯
其中 Wait函數使用前,要加鎖,使用後解鎖。 因爲wait內部實現是 先解鎖,阻塞住等待通知,接到通知後再加鎖。
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
// 做一個臨界區,環形隊列 [0 1 2 3 4]
var five [5]int // 共享隊列
var cond *sync.Cond // 條件變量
var mutex sync.Mutex // 鎖
// 控制生產者生產數量 最多5個
var cond_five *sync.Cond // 條件變量
var mutex_five sync.Mutex // 鎖
var prod_count int = 0
var customer_index int = 0
// 生產者
func productor() {
index := 0 // 生產下標
prodnum := 1000 //產品編號
for {
// 搶鎖
mutex.Lock()
// 生產商品
time.Sleep(time.Millisecond * 100)
five[index] = prodnum // 模擬生成商品
fmt.Println("I am productor,prodnum is",prodnum)
prodnum++
prod_count++ //產品數量增加
index = (index + 1) % 5 // 環形隊列
cond.Signal() // 喚醒一個go協程
// 釋放鎖
mutex.Unlock()
// 判斷是否可以繼續生成
if prod_count == 5 {
mutex_five.Lock()
cond_five.Wait()
mutex_five.Unlock()
}
}
wg.Done()
}
// 消費者
func customer(nu int) {
for {
// 搶鎖
mutex.Lock()
// wait
cond.Wait() // 多個go協程可能阻塞等待條件發生
// 消費
if prod_count > 0 {
time.Sleep(time.Millisecond * 10)
fmt.Printf("I am %d customer,prodnum is %d\n",nu,five[customer_index])
customer_index = (customer_index + 1) % 5
prod_count--
}
// 釋放鎖
mutex.Unlock()
cond_five.Signal() //通知生產者
}
wg.Done()
}
func main() {
cond = sync.NewCond(&mutex) // 構造條件變量
cond_five = sync.NewCond(&mutex_five)
wg.Add(2)
go productor()
go customer(1)
go customer(2)
wg.Wait()
}
1.5 channel通信與CSP併發模型
這個就是go的管道
Go 學習筆記08.協程和管道
https://blog.csdn.net/sunt2018/article/details/105585772
Go 學習筆記09.管道 常見操作
https://blog.csdn.net/sunt2018/article/details/105606943