golang,go,博客,开源,编程

errgroup与waitgroup比较

Published on with 0 views and 0 comments

errgroupWaitGroup 都是 Go 语言中用于并发编程的工具,但它们的功能和使用场景有所不同。我们可以通过对比这两个工具的特点来理解它们各自的优缺点以及应用场景。

1. WaitGroup(等待组)

sync.WaitGroup 是 Go 标准库中用于等待一组 Goroutine 执行完成的工具。它的核心功能是阻塞直到指定的所有 Goroutine 执行完毕。WaitGroup 不关心每个 Goroutine 执行的结果(即不关心错误),它仅仅是用来控制同步,确保所有 Goroutine 完成后再继续执行。

主要方法:

  • Add(delta int):增加或减少等待的 Goroutine 数量。
  • Done():通知 WaitGroup 当前 Goroutine 已经完成。
  • Wait():阻塞当前线程,直到所有 Goroutine 完成。

示例:

package main

import (
	"fmt"
	"sync"
)

func doTask(id int, wg *sync.WaitGroup) {
	defer wg.Done() // 完成时通知 WaitGroup
	fmt.Printf("Task %d is done\n", id)
}

func main() {
	var wg sync.WaitGroup
	for i := 1; i <= 3; i++ {
		wg.Add(1) // 添加一个待完成的任务
		go doTask(i, &wg)
	}
	wg.Wait() // 等待所有任务完成
	fmt.Println("All tasks are done")
}

缺点WaitGroup 不能处理任务中的错误,它只关心任务是否完成,而不管任务中发生了什么。


2. errgroup(错误组)

errgroupgolang.org/x/sync/errgroup 包中的一个工具,它是基于 WaitGroup 的扩展,但加入了错误处理的能力。除了等待所有 Goroutine 执行完毕外,errgroup 还能捕获 Goroutine 中发生的错误,并确保如果任何 Goroutine 返回错误时,能及时停止其他任务。

主要方法:

  • Go(func() error):启动一个新的 Goroutine,并指定该 Goroutine 执行的任务及返回的错误。
  • Wait():等待所有 Goroutine 完成,如果有任何一个 Goroutine 返回错误,Wait() 会立即返回第一个错误,并停止其他任务。

示例:

package main

import (
	"fmt"
	"golang.org/x/sync/errgroup"
	"net/http"
)

func fetchURL(url string) error {
	// 模拟网络请求
	resp, err := http.Get(url)
	if err != nil {
		return fmt.Errorf("failed to fetch %s: %w", url, err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("non-200 response for %s: %d", url, resp.StatusCode)
	}
	fmt.Printf("Successfully fetched %s\n", url)
	return nil
}

func main() {
	var g errgroup.Group
	urls := []string{
		"https://example.com",
		"https://google.com",
		"https://nonexistenturl.com", // 这个会失败
	}

	// 启动多个 Goroutine 来抓取网页
	for _, url := range urls {
		url := url // 捕获局部变量
		g.Go(func() error {
			return fetchURL(url)
		})
	}

	// 等待所有任务完成,如果遇到错误,返回第一个错误
	if err := g.Wait(); err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Println("All URLs fetched successfully!")
	}
}

优点

  • 自动错误处理errgroup 会自动收集和返回 Goroutine 执行中的第一个错误。
  • 错误传播:当任何一个任务出错时,errgroup 会停止剩余的任务,并返回错误。
  • 简单统一:无需手动管理每个 Goroutine 的错误,可以集中处理。

3. errgroupWaitGroup 的对比

特性WaitGrouperrgroup
错误处理不处理错误,无法集中管理错误。集中处理错误,返回第一个遇到的错误。
任务停止无法在任务出错时停止其他 Goroutine。可以在某个任务出错时停止其他 Goroutine。
适用场景适合只关心所有 Goroutine 是否完成的场景。适合关心 Goroutine 错误的场景,尤其是当出错时需要立即停止其他任务。
返回值无法返回错误,只能等待任务完成。返回任务执行中的第一个错误。
API 简洁度API 简单,只需要AddDoneWaitAPI 比较灵活,增加了Go(func() error)和错误处理机制。

4. 何时使用 errgroup

  • 当你启动多个并发任务时,并且这些任务可能会遇到错误,且你需要在第一个任务出错时停止其他任务的执行。
  • 需要集中管理所有任务的错误,而不想为每个任务单独处理错误。

5. 何时使用 WaitGroup

  • 当你只关心所有 Goroutine 是否完成,而不需要关注每个任务中的错误时。
  • 适用于执行任务并等待其完成的场景,且任务本身不涉及复杂的错误处理。

总结:

  • WaitGroup 适合用在没有错误处理需求的场景,它只关心任务是否完成。
  • errgroup 更适用于需要处理多个并发任务,并且需要集中管理错误的场景。它让你在并发任务中遇到第一个错误时能够及时停止其他任务,并返回错误。

标题:errgroup与waitgroup比较
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/01/07/1736231644542.html
联系:scotttu@163.com