Golang 中的并发模型中有哪些常见的错误?

在 Golang 的并发模型中,由于多个 goroutine 同时操作共享资源,容易出现一些并发错误。

常见的并发错误有:

  1. 竞争条件(Race Condition):多个 goroutine 同时访问某个资源,导致最终结果出错。
    例如:
var counter = 0

func inc() {
    counter++ 
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        ``` func() {
            defer wg.Done()
            for j := 0; j < 1000; j++ {
                inc()
            }
        }()
    }
    wg.Wait()
    println(counter)  // 最终结果是未知的
}

这里多个 goroutine 同时调用 inc(),从而导致 counter 最终的值是未知的。这个就是典型的竞争条件错误。

  1. 死锁(Deadlock):两个或多个 goroutine 相互等待对方占有的资源,导致永久阻塞。

例如:

var lock1 = sync.Mutex{} 
var lock2 = sync.Mutex{}

func foo() {
    lock1.Lock()
    lock2.Lock()  // 锁定lock2

    // ...

    lock2.Unlock()
    lock1.Unlock()
} 

func bar() {
    lock2.Lock()
    lock1.Lock()  // 锁定lock1

    // ...

    lock1.Unlock()
    lock2.Unlock()
}

func main() {
    go foo()
    go bar()
}

foo 和 bar goroutine 相互等待对方锁定的资源,最终导致程序无限阻塞。

  1. 洪水泛滥(Flooding):一个或多个快速执行的 goroutine 产生大量的请求或数据,拖慢其他 goroutine 的执行速度。

例如:

func doWork(jobs <-chan int, results chan<- int) { 
    for j := range jobs {
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    go doWork(jobs, results)

    for i := 0; i < 10; i++ {
        go func() {
            for {
                jobs <- 1
            }
        }() 
    }
}

这里 10 个 goroutine 快速发送 job,最终会导致 doWork goroutine 来不及处理,产生大量积压请求。这就是典型的洪水泛滥错误。
所以并发编程中,我们最需要注意的是竞争条件和死锁等并发错误。通过互斥锁、通信与同步等手段可以尽量避免这些错误的发生。