golang sync.WaitGroup 用法

本文介绍了Golang中sync.WaitGroup的用法,作为替代time.Sleep()等待协程完成的解决方案。WaitGroup通过计数器实现同步,初始值为0,通过Add()设置计数,Done()递减,Wait()阻塞直到计数为0。同时强调了使用WaitGroup时需要注意计数器不能为负,以及在传递时需传址,避免复制导致的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

执行一个简单协程

package main

import (
    "fmt"
    "time"
)

func main(){
    for i := 0; i < 100 ; i++{
        go fmt.Println(i)
    }
    time.Sleep(time.Second)
}

分析:

为什么会有sleep 呢, 主线程为了等待goroutine都运行完毕, 不得不在程序的末尾使用time.Sleep()来睡眠一段时间, 等待 其他线程充分运行 。对于简单的代码100 个for 循环可以在1秒内运行完但是实际的场景中大部分是1秒不够的, 而且大部分的时间 我们都无法预测for 循环内的代码运行时间的长短, 这个时候就不能使用time.sleep() 来完成等待操作了。

使用管道来 完成 操作

func main() {
    c := make(chan bool, 100)
    for i := 0; i < 100; i++ {
        go func(i int) {
            fmt.Println(i)
            c <- true
        }(i)
    }

    for i := 0; i < 100; i++ {
        <-c
    }
}

通道是可以完全达到目的的
但是在这里 管道会 有些大材小用,因为它被设计出来不仅仅只是在这里用作简单的同步处理,在这里使用管道实际上是不合适的。而且假设我们有一万、十万甚至更多的for循环,也要申请同样数量大小的管道出来,对内存也是不小的开销

对于这种情况, go 语言中有一个其他的工具 sync.WaitGroup 能更加方便的达到这个目的。
WaitGroup对象内部有个计时器, 最初从0 开始, 他有3个方法 Add() , Done(), Wait()用来控制计数器的数量。 Add(n) 把计数器设置成n, Done() 每次把计数器-1, wait() 会阻塞代码的运行, 直到计数器的值减为0

将上面代码修改:

func main() {
    wg := sync.WaitGroup{}
    wg.Add(100)
    for i := 0; i < 100; i++ {
        go func(i int) {
            fmt.Println(i)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

这里计数器设置为 100 每个for 循环运行完毕都把计数器减1 主函数中使用Wait() 一直阻塞, 直到wg为0 也就是所有的 100 个for 循环都运行完毕, 相对于使用 管道来说 WaitGroup轻巧了很多。

注意的事项 使用waitGroup

计数器不能为负

我们不能使用Add()给wg 设置一个负值 否则代码会报错

panic: sync: negative WaitGroup counter

goroutine 1 [running]:
sync.(*WaitGroup).Add(0xc042008230, 0xffffffffffffff9c)
    D:/Go/src/sync/waitgroup.go:75 +0x1d0
main.main()
    D:/code/go/src/test-src/2-Package/sync/waitgroup/main.go:10 +0x54

同样使用done() 也要特别注意不能把计数器的值设置为负值

WaitGroup 对象不是一个引用类型, 在通过函数传值的时候需要使用地址

waitGroup 对象不是一个引用类型, 在通过函数传值的时候需要使用地址

func main() {
    wg := sync.WaitGroup{}
    wg.Add(100)
    for i := 0; i < 100; i++ {
        go f(i, &wg)
    }
    wg.Wait()
}

// 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup) { 
    fmt.Println(i)
    wg.Done()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值