• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

go goroutine 怎样更好的进行错误处理

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

在 Go 语言程序开发中,goroutine 的使用是比较频繁的,因此在日常编码的时候 goroutine 里的错误处理,怎么做会比较好呢?

一般我们的业务代码如下:

func main() {
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		//... 业务逻辑
		wg.Done()
	}()
	go func() {
		//... 业务逻辑
		wg.Done()
	}()
	wg.Wait()
}

在上面的代码中,我们运行了多个 goroutine,每个协程又是单独行动的,想要抛出 error 错误信息,也不怎么明智。

通过错误日志记录

常用的第一种方法:通过把错误记录写入到日志文件中,再结合相关的 logtail 进行采集和梳理。

但这又会引入新的问题,那就是调用错误日志的方法写的到处都是,代码结构也比较乱、不直观。

最重要的是无法针对 error 做特定的逻辑处理和流转。

利用 channel 传输

大家可能会想到 Go 的经典哲学:不要通过共享内存来通信,而是通过通信来实现内存共享(Do not communicate by sharing memory; instead, share memory by communicating)。

第二种方法:利用 channel 来传输多个 goroutine 中的 errors:

func main() {
	cherrors := make(chan error)
	wgDone := make(chan bool)

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		//... 业务逻辑
		wg.Done()
	}()
	go func() {
		//... 业务逻辑
		err := returnErr()
		if err != nil {
			cherrors <- err
		}
		wg.Done()
	}()
	go func() {
		wg.Wait()
		close(wgDone)
	}()

	select {
	case <-wgDone:
		break
	case err := <-cherrors:
		close(cherrors)
		fmt.Println(err)
	}

	time.Sleep(time.Second)
}

func returnErr() error {
	return errors.New("出错啦。。我是错误信息")
}

虽然使用 channel 后已经方便了不少,但编写 channel 还要关心一些非业务向的逻辑。

使用 sync/errgroup

第三种方法,就是使用官方提供的 golang.org/x/sync/errgroup 标准库:

type Group
    func WithContext(ctx context.Context) (*Group, context.Context)
    func (g *Group) Go(f func() error)
    func (g *Group) Wait() error
  • Go:启动一个协程,在新的 goroutine 中调用给定的函数。
  • Wait:等待协程结束,直到 Go 方法中的所有函数调用都返回,然后返回其中第一个非零错误(如果有错误的话)。

结合其特性能够非常便捷的针对多 goroutine 进行错误处理:

func main() {
	group := new(errgroup.Group)

	nums := []int{-1, 0, 1}
	for _, num := range nums {
		num := num
		group.Go(func() error {
			res, err := output(num)
			fmt.Println(res)
			return err
		})
	}

	if err := group.Wait(); err != nil {
		fmt.Println("Get errors: ", err)
	} else {
		fmt.Println("Get all num successfully!")
	}
}

func output(num int) (int, error) {
	if num < 0 {
		return 0, errors.New("math: square root error!")
	}
	return num, nil
}

每启动一个新的 goroutine 都直接使用 Group.Go 方法,在等待和错误处理上使用 Group.Wait 方法。

这种方法进行错误处理的好处是不需要关注非业务逻辑的控制代码,比较简洁明了。

总结

在 Go 语言中,goroutine 是一种常用的方法,为此我们需要更了解 goroutine 的一系列相关知识,像是 context、error处理等

在团队开发中,统一一定的规范,这样的代码阅读起来就会比较明朗,一些隐藏很深的 Bug 也会减少很多。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Wheretogo???发布时间:2022-07-10
下一篇:
用Go语言编写一门工具的终极指南发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap