MST

星途 面试题库

面试题:Go中使用sync包实现协程同步之WaitGroup原理

在Go语言里,使用sync.WaitGroup实现协程同步是很常见的操作。请详细阐述sync.WaitGroup的工作原理,包括其内部使用的计数器是如何运作的,以及Add、Done和Wait这几个方法之间的协作逻辑。
47.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

sync.WaitGroup工作原理

  1. 计数器
    • sync.WaitGroup内部维护一个计数器,用于记录需要等待完成的任务数量。这个计数器是一个无符号整数,它初始值为0。
  2. Add方法
    • Add方法用于增加计数器的值。通常在启动新的协程前调用Add方法,将计数器增加相应的数量,表明后续会有这么多协程需要等待完成。例如,如果要启动5个协程,就可以调用Add(5)
    • 如果Add方法传入的参数是负数,会导致运行时恐慌(panic)。
  3. Done方法
    • Done方法是Add(-1)的便捷写法。每个协程在完成其任务后,调用Done方法,将计数器的值减1。这表示该协程已经完成了任务,等待组可以少等待一个任务。
  4. Wait方法
    • Wait方法会阻塞调用它的协程,直到计数器的值变为0。当所有需要等待的协程都调用了Done方法,计数器减为0,Wait方法才会返回,阻塞的协程得以继续执行。

协作逻辑示例

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(3) // 启动3个协程,所以计数器设为3

    go func() {
        defer wg.Done() // 协程结束时,计数器减1
        fmt.Println("协程1完成任务")
    }()

    go func() {
        defer wg.Done()
        fmt.Println("协程2完成任务")
    }()

    go func() {
        defer wg.Done()
        fmt.Println("协程3完成任务")
    }()

    wg.Wait() // 主线程阻塞,直到计数器为0
    fmt.Println("所有协程已完成任务")
}

在上述代码中,主线程调用wg.Add(3)增加计数器,3个协程在完成任务后调用wg.Done()减少计数器,主线程通过wg.Wait()等待计数器归零,确保所有协程完成任务后再继续执行后续代码。