Administrator
发布于 2023-11-24 / 106 阅读
0
0

Go sync.Waitgroup使用

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可以帮助我们实现并发地执行多个任务,然后等待它们都完成的功能。它是一个简单而强大的工具,可以用于处理各种并发场景。


评论