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