golang 之 计数器WaitGroup

        WaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法: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()
}

这里首先把wg 计数设置为100, 每个for循环运行完毕都把计数器减一,主函数中使用Wait() 一直阻塞,直到wg为零——也就是所有的100个for循环都运行完毕。相对于使用管道来说,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()
}

在前面提供的Go语言下载文件示例中,我们通过读取标准输入来阻止程序提前退出。这种方式虽然简单有效,但在更复杂的场景下显得不够专业和可靠。我们可以使用 `sync.WaitGroup` 来精确地管理并发 Goroutines 的生命周期,从而让整个流程更加可控。 下面是经过改造后的版本: ```go package main import ( "fmt" "io/ioutil" "net/http" "os" "sync" ) // 下载单个文件的任务函数 func downloadFile(filename string, url string, wg *sync.WaitGroup) { defer wg.Done() // 每当一个goroutine完成工作时通知WaitGroup减少计数器 resp, err := http.Get(url) if err != nil { fmt.Println(err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println(err) return } err = ioutil.WriteFile(filename, body, 0644) if err != nil { fmt.Println(err) return } fmt.Printf("Downloaded %s\n", filename) } func main() { var wg sync.WaitGroup urls := map[string]string{ "file1.txt": "http://example.com/file1", "file2.txt": "http://example.com/file2", } for fileName, fileURL := range urls { wg.Add(1) // 增加wg计数表示新增了一个待完成任务 go downloadFile(fileName, fileURL, &wg) } wg.Wait() // 主线程会一直阻塞在这里直到所有的子goroutines都完成了它们的工作 fmt.Println("All downloads completed.") } ``` 在这个改进版里,我们在每次创建一个新的 Goroutine 后调用一次 `Add(1)` 来告诉 WaitGroup 我们增加了一项新任务;而在每个 task 完成后自动减少对应的数量(`Done`)。最终当我们确认所有 tasks 都已经提交并且没有任何剩余未完成 work items 存在于 system 中之后再继续向下执行剩下的部分(main thread 继续往下走),因此保证了主函数不会比子协程先结束。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值