go学习笔记-goroutine竞争状态

如果两个或者多个goroutine在没有相互同步状态的情况下同时访问某个资源,并且同时对这个资源进行读写的时候,对于这个资源就处于相互竞争状态(race candition)。下面来看一个相互竞争的例子。

var number int
var wait sync.WaitGroup
func main()  {
    wait.Add(2)
    go updateNumber(20000)//加20000
    go updateNumber(30000)//加30000
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    for i:=0;i<addNumber ;i    {
        number   
    }
    wait.Done()
}

上面这个例子,我们期望得到的值应该是500000,但是我们最后得到值,并不是500000,而且每次得到的结果是不一样的。这是为什么呢?因为在两个goroutine中没有同步number的当前值,就会存在两个goroutinenumber值重复赋值的问题,造成值覆盖。这样就得不到我们预期的结果。

上面的例子我们可以看到,如果没有对竞争的资源进行有效的管理以及合理的处理,并发程序就会变的很复杂,并且会产生一些意想不到的错误。所以我们需要对竞争资源进行管理来避免这些问题。Go中提供一些传统的方式来处理这类问题

原子函数 atomic

原子函数能够以很底层的加锁机制来同步访问整型变量和指针,我们可以使用原子函数来处理竞争问题。

var number int32
var wait sync.WaitGroup
func main()  {
    wait.Add(2)
    go updateNumber(20000)
    go updateNumber(30000)
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    defer wait.Done()
    for i:=0;i<addNumber ;i    {
        atomic.AddInt32(&number,1)
    }

}

这里我们使用了atmoic包的AddInt32 函数。这个函数会同步整型值的加法,方法是强制同一时刻只能有一个goroutine 运行并完成这个加法操作。当goroutine试图去调用任何原子函数时,这些goroutine 都会自动根据所引用的变量做同步处理。atmoic包中还提供了LoadStore方法,对资源进行安全的读与写。

互斥锁 mutex

另一种方式是创建一个互斥锁来锁住一个区域,来保证同一个资源不会被同时修改或者使用。保证当前只有一个goroutine在执行当前区域的代码。

var (
    number int32
    wait sync.WaitGroup
    mutex sync.Mutex
    )
func main()  {
    wait.Add(2)
    go updateNumber(20000)
    go updateNumber(30000)
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    defer wait.Done()
    for i:=0;i<addNumber ;i    {
        mutex.Lock() // 加锁
        number  ;
        mutex.Unlock() //释放锁
    }
}

上面的代码片段,在Number改变的前后对当前区域加锁,最后也能得到我们的目的,但是这样的会话,每次在number变更的时候,都会创建锁与释放锁,会对性能产生很大的影响。其实我们可以在for循环区域来加锁。

func updateNumber(addNumber int)  {
    defer wait.Done()
    mutex.Lock() // 加锁
    for i:=0;i<addNumber ;i    {
        number  ;
    }
    mutex.Unlock() //释放锁
}

后面这种形式的效率明显是要比第一种高很多的。所以我们程序有使用互斥锁的话,需要考虑加锁的粒度问题。

虽然上面上面两种方式也可以解决竞争问题,但是在go中有一种更好的方式来解决这个问题,那就是goroutine的好兄弟channel。由于channel的内容比较多,所以我将单独写一个笔记来记录这方面的问题。期待下一篇的更新

期待一起交流

file

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值