企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 一、概念 * go中channel实现了同步,确保并发安全,同时也提供了锁的操作方式 * go中sync包提供了锁相关的支持 * Mutex:以加锁方式解决并发安全问题 * sync.WaitGroup:用来等待一组子协程的结束,需要设置等待的个数,每个子协程结束后要调用Done(),最后在主协程中Wait()即可。 Add():添加计数 Done():操作结束时调用,计数减1 Wait():等待所有操作结束 ## 二、加锁与不加锁的区别 #### 不加锁 ~~~ package main import ( "time" "fmt" ) //账户 type Account struct { money int } //模拟安全校验的 func (a *Account) Check() { time.Sleep(time.Second) } //设置余额 func (a *Account) SetAccount(n int) { a.money += n } //查询余额 func (a *Account) GetAccount() int { return a.money } //买东西 func (a *Account) Buy(n int) { if a.money > n { a.Check() a.money -= n } } func main() { var account Account account.SetAccount(100) //开2个协程买东西 go account.Buy(60) go account.Buy(50) time.Sleep(2 * time.Second) fmt.Println(account.GetAccount()) } ~~~ 运行结果 -10 #### 加锁 ~~~ package main import ( "time" "fmt" "sync" ) //账户 type Account struct { money int flag sync.Mutex //设置锁 } //模拟安全校验的 func (a *Account) Check() { time.Sleep(time.Second) } //设置余额 func (a *Account) SetAccount(n int) { a.money += n } //查询余额 func (a *Account) GetAccount() int { return a.money } //买东西 func (a *Account) Buy(n int) { //加锁 a.flag.Lock() if a.money > n { a.Check() a.money -= n } //解锁 a.flag.Unlock() } func main() { var account Account account.SetAccount(100) //开2个协程买东西 go account.Buy(60) go account.Buy(50) time.Sleep(2 * time.Second) fmt.Println(account.GetAccount()) } ~~~ 执行结果: 50 ## 三、如果主协程中没有内容子协程就不会去执行 #### 主协程没有内容 ~~~ package main import ( "fmt" ) func main() { go func() { fmt.Println("子协程1") }() go func() { fmt.Println("子协程2") }() } ~~~ 运行结果: #### 解决原理 ~~~ package main import ( "fmt" ) func main() { m1 := make(chan int) // 子协程活动个数 count :=2 go func() { fmt.Println("子协程1") // 协程1结束,发出信号 m1 <- 1 }() go func() { fmt.Println("子协程2") // 协程2结束,发出信号 m1 <- 1 }() for range m1{ //读一个数据 count-1 count -- if count ==0{ close(m1) } } } ~~~ 执行结果: 子协程2运行 子协程1运行 #### 使用 sync.WaitGroup 解决 ~~~ package main import ( "sync" "fmt" ) func main() { //声明等待组 var wg sync.WaitGroup wg.Add(2) go func() { fmt.Println("子协程1运行") wg.Done() }() go func() { fmt.Println("子协程2运行") wg.Done() }() wg.Wait() } ~~~ 执行结果: 子协程2运行 子协程1运行