MST

星途 面试题库

面试题:Go语言WaitGroup与其他同步原语的比较及选择策略

对比Go语言中的WaitGroup与其他同步原语(如Mutex、Channel等),在功能、性能和适用场景上有哪些异同?在复杂的并发编程场景下,如何根据具体需求选择最合适的同步原语?请结合具体代码示例分析。
29.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

1. 功能对比

  • WaitGroup:用于等待一组 goroutine 完成。它有一个计数器,每个需要等待的 goroutine 启动前调用 Add 方法增加计数器,完成时调用 Done 方法减少计数器,主线程通过 Wait 方法阻塞,直到计数器归零。
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Goroutine %d is done\n", id)
        }(i)
    }
    wg.Wait()
    fmt.Println("All goroutines are done")
}
  • Mutex:互斥锁,用于保护共享资源,确保同一时间只有一个 goroutine 可以访问该资源,防止竞态条件。
package main

import (
    "fmt"
    "sync"
)

var (
    count int
    mu    sync.Mutex
)

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    mu.Lock()
    count++
    mu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    fmt.Println("Final count:", count)
}
  • Channel:用于 goroutine 之间的通信和同步。可以传递数据,并且可以通过关闭通道来通知接收方没有更多数据。
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int)
    go func() {
        for i := 0; i < 3; i++ {
            ch <- i
        }
        close(ch)
    }()
    for val := range ch {
        fmt.Println("Received:", val)
    }
}

2. 性能对比

  • WaitGroup:性能主要消耗在计数器的原子操作上,在等待大量 goroutine 时,性能开销相对较小,因为它主要是等待,不涉及资源竞争。
  • Mutex:在高并发场景下,如果频繁加锁解锁,会有一定的性能开销,因为涉及到操作系统的调度和上下文切换。
  • Channel:性能取决于数据的传输量和 goroutine 的数量。如果数据传输频繁且量大,会有一定的性能损耗,因为涉及到数据的拷贝和同步。

3. 适用场景对比

  • WaitGroup:适用于需要等待一组 goroutine 全部完成的场景,例如并行计算多个任务,最后汇总结果。
  • Mutex:适用于保护共享资源,防止多个 goroutine 同时访问造成数据不一致,如计数器、共享内存等场景。
  • Channel:适用于 goroutine 之间需要传递数据和同步的场景,如生产者 - 消费者模型。

4. 复杂并发场景下的选择

  • 如果需要等待一组任务完成,使用 WaitGroup。
  • 如果需要保护共享资源,使用 Mutex。
  • 如果需要在 goroutine 之间传递数据和同步,使用 Channel。
  • 在复杂场景下,可能会组合使用多种同步原语。例如,在一个生产者 - 消费者模型中,生产者和消费者之间通过 Channel 传递数据,同时如果消费者需要统计处理的数据量,可能会用到 Mutex 保护计数器,并且如果有多个生产者或消费者需要等待全部完成,可能会用到 WaitGroup。