协程锁

  • 什么是竞争
  • Mutex 的使用
什么是竞争

看下面的代码

package main

import (
    "sync"
    "fmt"
)

var total = 0

func add(num int,ws * sync.WaitGroup){
   total += 1
   ws.Done()
}

func main() {
  var ws sync.WaitGroup
  ws.Add(1000)
  for i:=0;i<1000;i++{
      go add(1,&ws)
  }
  ws.Wait()
  fmt.Println(total)
}

我们对一个变量total 进行1000次 +1 操作,不过我们是在多个协程中进行的,猜猜结果如何,我们运行五次看结果

1594482-1d6d52b5f66fbdbc
image.png
1594482-f2c8b65b07c4b2a7
image.png
1594482-11fbd76e66019e86
image.png
1594482-ff35de8071d6f5ea
image.png
1594482-341c0f7c2ac13548
image.png

竞争发生的概率,和你的协程数量成正比,如果你的协程数很少的话,可能运行几百次发现不了这个现象

那如何避免这个问题呢?


Mutex

Mutex 用于提供一种加锁机制(Locking Mechanism),可确保在某时刻只有一个协程在临界区运行,以防止出现竞态条件。

直接看代码

package main

import (
    "sync"
    "fmt"
)

var total = 0

func add(num int,ws * sync.WaitGroup,mutex *sync.Mutex){
    mutex.Lock()
   total += 1
   mutex.Unlock()
   ws.Done()
}

func main() {
  var ws sync.WaitGroup
    mutex := sync.Mutex{}
    ws.Add(1000)
  for i:=0;i<1000;i++{
      go add(1,&ws,&mutex)
  }
  ws.Wait()
  fmt.Println(total)
}

运行结果如下

1594482-1502ebb48c036990
image.png

sync.Mutex 是一个结构体 在操作元素的时候 mutex.Lock() 加锁 执行完毕后 mutex.Unlock()解锁


使用信道处理竞争
package main  
import (  
    "fmt"
    "sync"
    )
var x  = 0  
func increment(wg *sync.WaitGroup, ch chan bool) {  
    ch <- true
    x = x + 1
    <- ch
    wg.Done()   
}
func main() {  
    var w sync.WaitGroup
    ch := make(chan bool, 1)
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go increment(&w, ch)
    }
    w.Wait()
    fmt.Println("final value of x", x)
}

通过使用 Mutex 和信道,我们已经解决了竞态条件的问题。那么我们该选择使用哪一个?答案取决于你想要解决的问题。如果你想要解决的问题更适用于 Mutex,那么就用 Mutex。如果需要使用 Mutex,无须犹豫。而如果该问题更适用于信道,那就使用信道。:)

由于信道是 Go 语言很酷的特性,大多数 Go 新手处理每个并发问题时,使用的都是信道。这是不对的。Go 给了你选择 Mutex 和信道的余地,选择其中之一都可以是正确的。

总体说来,当 Go 协程需要与其他协程通信时,可以使用信道。而当只允许一个协程访问临界区时,可以使用 Mutex。

就我们上面解决的问题而言,我更倾向于使用 Mutex,因为该问题并不需要协程间的通信。所以 Mutex 是很自然的选择。

我的建议是去选择针对问题的工具,而别让问题去将就工具。:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值