设为首页 加入收藏

TOP

golang中的errgroup(二)
2023-07-23 13:29:46 】 浏览:65
Tags:golang errgroup
f err != nil { fmt.Println("获取文件错误") return } }() // 阻塞等待计数器小于等于0 wg.Wait() // 填充 for i, courseware := range coursewares { if user, ok := users[courseware.CreateId]; ok { coursewares[i].CreateName = user.Name } if file, ok := files[courseware.CoverId]; ok { coursewares[i].CoverPath = file.Path } } fmt.Println(coursewares) } ...

我们初始化一个sync.WaitGroup,调用wg.Add(1)给计数器加一,调用wg.Done()计数器减一,wg.Wait()阻塞等待直到计数器小于等于0,结束阻塞,继续往下执行。

3、errgroup

但是我们现在又有这样的需求,我们希望如果获取用户或者获取文件有任何一方报错了,直接抛错,不再组装数据。

我们可以像下面这样写

...

var goErr error
var wg sync.WaitGroup

...

func main() {
	...

	// 此处放到协程里
	wg.Add(1)
	go func() {
		defer wg.Done()
		// 批量获取用户信息
		users, err = UserMap(userIds)
		if err != nil {
			goErr = err
			fmt.Println("获取用户错误:", err)
			return
		}
	}()

	// 此处放到协程里
	wg.Add(1)
	go func() {
		defer wg.Done()
		// 批量获取文件信息
		files, err = FileMap(fileIds)
		if err != nil {
			goErr = err
			fmt.Println("获取文件错误:", err)
			return
		}
	}()

	wg.Wait()

	if goErr != nil {
		fmt.Println("goroutine err:", err)
		return
	}

	...
}

...

把错误放在goErr中,结束阻塞后判断协程调用是否抛错。

golang里面有没有类似这样的实现呢?答案是有的,那就是errgroup。其实和我们上面的方法差不多,但是errgroup包做了一层结构体的封装,也不需要在每个协程里面判断error传给errGo了。

下面是errgroup的实现

package main

import (
	"errors"
	"fmt"
	"golang.org/x/sync/errgroup"
	"time"
)

type Courseware struct {
	Id         int64
	Name       string
	Code       string
	CreateId   int64
	CreateName string
	CoverId   int64
	CoverPath string
}

type User struct {
	Id   int64
	Name string
}

type File struct {
	Id   int64
	Path string
}

var coursewares []Courseware
var users map[int64]User
var files map[int64]File
var err error
// 定义一个errgroup
var eg errgroup.Group

func main() {
	// 查询课件
	coursewares, err = CoursewareList()
	if err != nil {
		fmt.Println("获取课件错误:", err)
		return
	}

	// 获取用户ID、文件ID
	userIds := make([]int64, 0)
	fileIds := make([]int64, 0)
	for _, courseware := range coursewares {
		userIds = append(userIds, courseware.CreateId)
		fileIds = append(fileIds, courseware.CoverId)
	}


	// 此处放到协程里
	eg.Go(func() error {
		// 批量获取用户信息
		users, err = UserMap(userIds)
		if err != nil {
			fmt.Println("获取用户错误:", err)
			return err
		}
		return nil
	})

	// 此处放到协程里
	eg.Go(func() error {
		// 批量获取文件信息
		files, err = FileMap(fileIds)
		if err != nil {
			fmt.Println("获取文件错误:", err)
			return err
		}
		return nil
	})

  // 判断group中是否有报错
	if goErr := eg.Wait(); goErr != nil {
		fmt.Println("goroutine err:", err)
		return
	}

	// 填充
	for i, courseware := range coursewares {
		if user, ok := users[courseware.CreateId]; ok {
			coursewares[i].CreateName = user.Name
		}

		if file, ok := files[courseware.CoverId]; ok {
			coursewares[i].CoverPath = file.Path
		}
	}
	fmt.Println(coursewares)
}

func UserMap(ids []int64) (map[int64]User, error) {
	time.Sleep(3 * time.Second)
	return map[int64]User{
		1: {Id: 1, Name: "liu"},
		2: {Id: 2, Name: "kang"},
	}, errors.New("sql err")
}

func FileMap(ids []int64) (map[int64]File, error) {
	time.Sleep(3 * time.Second)
	return map[int64]File{
		1: {Id: 1, Path: "/a/b/c.jpg"},
		2: {Id: 2, Path: "/a/b/c/d.jpg"},
	}, nil
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇golang中的nil接收器 下一篇golang中的字符串

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目