sync.Waitgroup的使用
在Go语言中,有时我们需要并发地执行多个任务,然后等待它们都完成后再继续后续的操作。刚好今天能够应用上,是这样:使用多线程消费队列,需要等到所有操作执行完再次读取消息。例如,我们可能需要从多个数据源获取数据,然后汇总结果。这种场景下,我们可以使用sync.Waitgroup来实现。
sync.Waitgroup是一个结构体,它提供了三个方法:Add,Done和Wait。Add方法用于增加等待组的计数器,表示有多少个任务需要等待。Done方法用于减少等待组的计数器,表示一个任务已经完成。Wait方法用于阻塞当前的goroutine,直到等待组的计数器变为零,表示所有的任务都已经完成。【与Java 中的 CountDownLatch
差不多,相比之下CountDownLatch貌似只能固定一个数值, Waitgroup具有Add比较灵活】
下面是一个简单的例子,演示了如何使用sync.Waitgroup来并发地从三个不同的网站获取数据,然后打印出总的字节数:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"sync"
)
func main() {
// 创建一个等待组
var wg sync.WaitGroup
// 定义一个切片,存放三个网站的URL
urls := []string{
"https://www.bing.com",
"https://www.google.com",
"https://www.yahoo.com",
}
// 定义一个变量,用于存放总的字节数
var totalBytes int
// 遍历切片,为每个URL创建一个goroutine
for _, url := range urls {
// 增加等待组的计数器
wg.Add(1)
// 创建一个匿名函数,传入URL作为参数
go func(url string) {
// 使用defer语句,确保在函数返回时调用Done方法
defer wg.Done()
// 发起HTTP请求,获取响应
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
return
}
// 读取响应的内容
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return
}
// 关闭响应的主体
resp.Body.Close()
// 获取响应的字节数
bytes := len(body)
// 打印URL和字节数
fmt.Printf("%s: %d bytes\n", url, bytes)
// 累加总的字节数
totalBytes += bytes
}(url) // 调用匿名函数,传入URL作为参数
}
// 等待所有的goroutine完成
wg.Wait()
// 打印总的字节数
fmt.Printf("Total: %d bytes\n", totalBytes)
}
运行结果如下:
https://www.bing.com: 104857 bytes
https://www.google.com: 13107 bytes
https://www.yahoo.com: 301798 bytes
Total: 419762 bytes
从上面的例子可以看出,sync.Waitgroup可以帮助我们实现并发地执行多个任务,然后等待它们都完成的功能。它是一个简单而强大的工具,可以用于处理各种并发场景。