go 竟态

作者: 阳光的小mi | 来源:发表于2019-10-27 00:18 被阅读0次

什么是竟态

当多个routine共享同一资源时就会出现竟态。比如多个routine对同一个全局变量进行+1操作而导致数据操作不准确。
示例:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var count int
    var arithmetic sync.WaitGroup
    Increment := func() {
        count++
    }
    Decrement := func() {
        count--
    }
    for j := 0; j < 100; j++ {
        arithmetic.Add(1)
        go func() {
            defer arithmetic.Done()
            Increment()
        }()
    }
    for i := 0; i < 100; i++ {
        arithmetic.Add(1)
        go func() {
            defer arithmetic.Done()
            Decrement()
        }()
    }
    arithmetic.Wait()
    fmt.Println("count", count)
}

上面这个程序,100个routine并发执行count++;100个routine并发执行count--;最后结果是多少?


执行结果-竟态

上述代码就出现了竟态,两个for循环一共产生200个routine并发操作全局变量count,多个routine读取到同一count的值进行加减操作,最后导致count虽然执行了100次+1和100次-1,但最终结果却不为0

sync.Mutex加锁

我们再来看看下面这个程序

package main

import (
    "fmt"
    "sync"
)

func main() {
    var count int
    var lock sync.Mutex
    var arithmetic sync.WaitGroup
    Increment := func(i int) {
        fmt.Println("Inc", i, "waiting the lock")
        lock.Lock()
        fmt.Println("Inc", i, "lock the lock", count)
        defer lock.Unlock()
        count++
        fmt.Println("Inc", i, "unlock the lock", count)
        fmt.Println()
    }
    Decrement := func(i int) {
        fmt.Println("Dec", i, "waiting the lock")
        lock.Lock()
        fmt.Println("Dec", i, "lock the lock", count)
        defer lock.Unlock()
        count--
        fmt.Println("Dec", i, "unlock the lock", count)
        fmt.Println()
    }
    for j := 0; j < 100; j++ {
        arithmetic.Add(1)
        go func(i int) {
            defer arithmetic.Done()
            Increment(i)
        }(j)
    }
    for i := 0; i < 100; i++ {
        arithmetic.Add(1)
        go func(i int) {
            defer arithmetic.Done()
            Decrement(i)
        }(i)
    }
    arithmetic.Wait() 
    fmt.Println("count", count)
}
执行结果-截取一部分

通过sync.Mutex加锁的方式阻塞routine抢夺同一资源,虽然解决了竟态的问题,但也失去了routine的作用,代码相当于是在顺序执行。

结语

我们在用routine的时候一定要避免竟态的出现,另外网上有很多检测竟态的方法可以用起来。

相关文章

  • go 竟态

    什么是竟态 当多个routine共享同一资源时就会出现竟态。比如多个routine对同一个全局变量进行+1操作而导...

  • go 竞态检测

    Go 工具套件在 Go 版本 1.1 引入了一个竞态检测工具(race detector)。这个竞态检测工具是在编...

  • 竟态条件 racing condition

    多个线程读时,线程是安全的。当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。我的理解,竞态条...

  • 短语归集2020-04-20

    adopt 采纳 adapt 改编,以适应 go so far as to 竟到了===程度 embark on ...

  • java高并发-静态synchronized方法和非静态sync

    java高并发-静态synchronized方法和非静态synchronized方法是否存在竟态我们都知道,syn...

  • java高并发-Thread.start()的执行流程

    本来讲完《静态synchronized方法和非静态synchronized方法是否存在竟态》这篇之后,想给大家讲一...

  • 来了 风和日丽 来了 灯红酒绿 来了 趣味人生 世间百态 还要多久尝尽 世态炎凉 笑看人间百态 竟是个千疮百孔 竟...

  • GO 同步原语与锁

    Go 语言作为一个原生支持用户态进程(Goroutine)的语言,当提到并发编程、多线程编程时,往往都离不开锁这一...

  • 携手天下(25)

    携手天下 目录 二十五章(宴会百态中) “祖母,”南宫玉竟就这么跑到太后身边,就那么...

  • Golang aoit

    在 Go 里是 —— 不变的。它们在编译时生成,即便是局部定义在函数里。它只能是数,字串或布尔。因为编译态的限制,...

网友评论

      本文标题:go 竟态

      本文链接:https://www.haomeiwen.com/subject/epxpvctx.html