MST

星途 面试题库

面试题:Go的WaitGroup在复杂场景下的应用

假设有一个任务系统,其中有多个子任务需要并发执行,并且每个子任务执行完成后需要更新全局的任务进度。在这种场景下,如何合理使用WaitGroup,同时避免竞态条件,详细说明代码实现思路。
48.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 引入必要的包
    package main
    
    import (
        "fmt"
        "sync"
    )
    
  2. 定义全局变量
    var (
        taskProgress int
        mu           sync.Mutex
    )
    
    • taskProgress 用于记录全局任务进度。
    • mu 是一个互斥锁,用于避免竞态条件,保护对 taskProgress 的访问。
  3. 子任务函数
    func subTask(wg *sync.WaitGroup) {
        defer wg.Done()
        // 模拟子任务执行
        // 这里省略具体的业务逻辑
        mu.Lock()
        taskProgress++
        mu.Unlock()
    }
    
    • 子任务函数接受一个 WaitGroup 指针。
    • 使用 defer wg.Done() 来标记子任务完成。
    • 在更新 taskProgress 之前,先获取互斥锁 mu,更新完成后释放互斥锁,以此避免竞态条件。
  4. 主函数
    func main() {
        var wg sync.WaitGroup
        numSubTasks := 10
        for i := 0; i < numSubTasks; i++ {
            wg.Add(1)
            go subTask(&wg)
        }
        wg.Wait()
        fmt.Printf("All sub - tasks completed. Total progress: %d\n", taskProgress)
    }
    
    • main 函数中,初始化一个 WaitGroup
    • 循环创建多个子任务,并为每个子任务调用 wg.Add(1) 来增加等待组的计数。
    • 使用 go 关键字启动子任务协程。
    • 最后调用 wg.Wait() 等待所有子任务完成,然后输出全局任务进度。

总结来说,通过 WaitGroup 来同步多个并发子任务的执行,确保所有子任务完成后再进行后续操作,通过 Mutex 来保护对全局任务进度变量 taskProgress 的并发访问,避免竞态条件。