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

相关文章
相关标签/搜索