MST

星途 面试题库

面试题:Go WaitGroup并发控制精度优化时可能遇到的问题

在对Go WaitGroup进行并发控制精度优化过程中,可能会遇到哪些常见问题,例如竞态条件、资源泄漏等,请详细分析并说明如何避免这些问题。
31.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

常见问题及分析

  1. 竞态条件
    • 分析:在使用 WaitGroup 时,如果多个 goroutine 同时对 WaitGroup 进行操作(如 AddDoneWait),可能会出现竞态条件。例如,一个 goroutine 还未完成 Add 操作,另一个 goroutine 就开始执行 Wait,可能导致 Wait 提前返回,因为 Wait 依赖于 Add 设置的计数。
    • 示例代码
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            // 模拟一些工作
            fmt.Println("Working")
        }()
    }
    // 这里如果没有wg.Wait(),程序可能在所有goroutine完成前就退出
    // 可能出现竞态,如wg计数还未正确设置,程序就尝试等待
}
  1. 资源泄漏
    • 分析:如果一个 goroutine 调用了 Add 但没有相应的 Done 调用,Wait 将会永远阻塞,导致资源泄漏。例如,在 goroutine 中发生了 panic 而没有恢复,就可能导致 Done 未被调用。
    • 示例代码
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer func() {
            if r := recover(); r != nil {
                fmt.Println("Recovered from panic:", r)
            }
        }()
        panic("Something went wrong")
        wg.Done()
    }()
    wg.Wait()
    fmt.Println("All goroutines completed")
}
  1. 错误的计数操作
    • 分析:不正确地设置 Add 的计数,例如设置的计数大于实际要等待的 goroutine 数量,或者在不必要的地方多次调用 Add,可能导致 Wait 等待时间过长或出现意外的阻塞。同样,多次调用 Done 超过 Add 设置的计数也会导致问题。
    • 示例代码
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(2) // 这里设置2,但实际只有1个goroutine
    go func() {
        defer wg.Done()
        fmt.Println("Working")
    }()
    wg.Wait()
    fmt.Println("All goroutines completed")
}

避免方法

  1. 避免竞态条件
    • 使用同步原语:确保对 WaitGroup 的操作是同步的。Go 语言本身对 WaitGroup 的实现已经在内部进行了同步,所以只要正确使用,一般不会出现竞态。在上述示例中,确保 Add 在 goroutine 启动前正确设置计数。
    • 按顺序操作:按照逻辑顺序调用 AddDoneWait。先调用 Add 设置计数,然后启动 goroutine,在 goroutine 完成工作后调用 Done,最后调用 Wait 等待所有 goroutine 完成。
  2. 避免资源泄漏
    • 使用 defer wg.Done():在启动的 goroutine 函数内部,使用 defer wg.Done() 确保无论函数正常结束还是发生 panic,Done 都会被调用。如上述第二个示例代码中,加入了 recover 机制处理 panic,同时确保 wg.Done() 能被调用。
    • 监控和日志:在代码中添加日志记录,监控 WaitGroup 的计数变化,以便在调试和生产环境中发现潜在的资源泄漏问题。
  3. 避免错误的计数操作
    • 仔细设置计数:在调用 Add 时,准确设置要等待的 goroutine 数量。可以通过循环等方式动态计算计数,确保设置正确。
    • 避免重复操作:确保 AddDone 只在必要时调用,并且调用次数匹配。例如,不要在循环内部多次调用 Add,除非逻辑上确实需要增加等待的 goroutine 数量。