巧妙的使用WaitGroup处理错误

1. 写在前面

微信公众号:[double12gzh]

个人主页: https://gzh.readthedocs.io

关注容器技术、关注Kubernetes。问题或建议,请公众号留言。

使用Go的众多好处之一是它在并发方面十分简单,而大家比熟悉的WaitGroups就是一个很好的例子。虽然在并发处理上十分的方便,但要想有效地处理并发和错误可能很棘手。

本篇文章旨在概述如何在不停止程序执行的情况下,运行多个goroutine并有效处理任何错误。

2. 具体实现

对于这个如何上,可以简单的概括为以下三点:

  • 两个channel。这两个channel的作用是用于传递错误传递WaitGroup何时完成
  • 一个groutine。主要作用是用于监听WaitGroup是否完成,如果完成了,将会关闭某个channel。
  • 一个Select。它用于监听出现的错误或WaitGroup完成与否,无论谁先结束,那么Select就会先执行谁。

具体代码如下:

package main

import (
	"errors"
	"fmt"
	"sync"
)

// ErrorHandler 返回一个错误。
func ErrorHandler() error {
	return errors.New("generated errors")
}

func main() {
	// 创建两个channel,一个用于传递错误,另一个表示WaitGroup是否结束。
	errCh := make(chan error)
	wgCh := make(chan bool)

	var wg sync.WaitGroup

	wg.Add(2)

	go func() {
		fmt.Println("WaitGroup 1st.")

		// 这里可以定义我们需要执行的操作

		wg.Done()
	}()

	go func() {
		fmt.Println("WaitGroup 2nd")

		// 返回自定义的错误
		if err := ErrorHandler(); err != nil {
			errCh <- err
		}

		wg.Done()
	}()

	go func() {
		wg.Wait()
		close(wgCh)
	}()

	// 当有错误返回或WaitGroup执行结束时会被执行。
	select {
	case <-wgCh:
		break
	case err := <-errCh:
		close(errCh)
		panic(err)
	}

	fmt.Println("Main func ended!")
}

运行上述代码,我们可以得到以下的输出,也从而能验证我们已经基于此达到了我们的目的。

PS C:\Users\jeffrey\Desktop\hello> go run main.go
WaitGroup 1st.
WaitGroup 2nd
panic: generated errors.

goroutine 1 [running]:
main.main()
        C:/Users/jeffrey/Desktop/hello/main.go:53 +0x2a6
exit status 2
PS C:\Users\jeffrey\Desktop\hello> 

欢迎关注我的微信公众号:

posted @ 2020-09-20 14:26  大海星  阅读(698)  评论(0编辑  收藏  举报