Go语言提供了多种机制来同步goroutines,确保并发程序的正确性和效率。

Go语言中用于goroutine同步的几种主要方式:

WaitGroup

sync.WaitGroup是用来等待一组goroutines完成的主要方式。

通过WaitGroup的Add方法来设定需要等待的goroutines数量,Done方法表示一个goroutine完成了它的工作,而Wait方法则阻塞调用它的goroutine,直到计数器为零。


var wg sync.WaitGroup

for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(i int) {
        defer wg.Done()
        // 执行任务
        fmt.Println("Goroutine", i, "finished")
    }(i)
}

wg.Wait() // 等待所有goroutine完成
fmt.Println("All goroutines finished")

Mutex(互斥锁)

sync.Mutex提供了一种保护共享资源的方式。

通过互斥锁,可以确保在任何时刻只有一个goroutine能访问该资源, 防止了并发写入导致的数据竞态。


var mu sync.Mutex
var counter int

func increment() {
    mu.Lock()
    defer mu.Unlock()
    counter++
}

// 在goroutines中调用increment

3. RWMutex读写锁

sync.RWMutex是一种特殊的互斥锁它允许多个goroutine同时读取一个资源但写入时则需要独占锁这在读多写少的场景下非常有用可以提高程序的并发性能

go

var rwMu sync.RWMutex
var data int

func readData() int {
    rwMu.RLock()
    defer rwMu.RUnlock()
    return data
}

func writeData(value int) {
    rwMu.Lock()
    defer rwMu.Unlock()
    data = value
}
  1. Channel

Channel是Go中实现goroutine之间通信的主要方式,同时它也可以用于同步。

例如,可以使用无缓冲的channel实现信号通知,确保特定事件的顺序。


done := make(chan bool)

go func() {
    // 执行任务
    fmt.Println("Goroutine finished work")
    done <- true // 发送完成信号
}()

<-done // 等待接收信号
fmt.Println("Main goroutine received signal")
  1. Context

context.Context类型用于控制goroutine的生命周期。它可以用来发送取消信号,可以优雅地取消正在执行的goroutine。


ctx, cancel := context.WithCancel(context.Background())

go func() {
    select {
    case <-ctx.Done():
        fmt.Println("Goroutine canceled")
        return
    default:
        // 执行正常逻辑
    }
}()

// 当需要取消goroutine时
cancel()

在实际开发中,合理选择和组合这些机制,可以构建出既安全又高效的并发程序。