MST
星途 面试题库

面试题:Go语言闭包在并发编程中的复杂性

在Go语言的并发编程环境下,闭包会带来哪些复杂性?请结合具体代码示例,阐述如何正确处理闭包在并发场景下的资源竞争、数据一致性等问题。
45.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

闭包在Go并发编程中的复杂性

  1. 资源竞争问题:闭包可能引用外部变量,在并发环境下多个协程同时访问和修改这些变量,就会导致资源竞争。
  2. 数据一致性问题:由于资源竞争,可能使得数据处于不一致的状态,例如某个变量的更新没有按照预期顺序完成。

代码示例及处理方法

package main

import (
    "fmt"
    "sync"
)

func main() {
    var count int
    var wg sync.WaitGroup
    var mu sync.Mutex

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            // 使用互斥锁来处理资源竞争
            mu.Lock()
            count++
            mu.Unlock()
        }()
    }

    wg.Wait()
    fmt.Println("Final count:", count)
}

在上述代码中,count 是被闭包引用的外部变量。通过使用 sync.Mutex 来加锁和解锁,确保每次只有一个协程能够修改 count,从而解决资源竞争和保证数据一致性。如果不使用 mu.Lock()mu.Unlock(),多个协程同时对 count 进行 ++ 操作,就会出现资源竞争,导致 count 的最终值可能小于预期的 10。

另外,还可以使用 sync/atomic 包来对一些基本类型(如 int)进行原子操作,这也是处理并发数据一致性问题的一种有效方式,例如:

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    var count int64
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            atomic.AddInt64(&count, 1)
        }()
    }

    wg.Wait()
    fmt.Println("Final count:", atomic.LoadInt64(&count))
}

这里使用 atomic.AddInt64atomic.LoadInt64int64 类型的 count 进行原子操作,避免了资源竞争,保证了数据一致性。