go goroutine 怎样更好的进行错误处理
前言
在 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 也会减少很多。
go goroutine 怎样更好的进行错误处理的更多相关文章
- KCL v0.4.6 alpha 发布!- 更多 Kubernetes 工具集成,更好的 IDE 错误提示
简介 KCL 团队很高兴地宣布 KCL v0.4.6-alpha.1 版本现在已经可用! 您可以在 KCL v0.4.6-alpha.1 发布页面 或者 KCL 官方网站 获得 KCL 二进制下载链接 ...
- EntityFramework6 版本更变产生的错误
LINQ to Entities does not recognize the method 'System.Nullable`1[System.Int32] DiffMinutes(System.N ...
- 【译】GO语言:管理多个错误
原文:https://medium.com/a-journey-with-go/go-multiple-errors-management-a67477628cf1 关于开发者使用Go遇到的最大挑 ...
- Golang通脉之错误处理
在实际工程项目中,总是通过程序的错误信息快速定位问题,但是又不希望错误处理代码写的冗余而又啰嗦.Go语言没有提供像Java.C#语言中的try...catch异常处理方式,而是通过函数返回值逐层往上抛 ...
- PHP 的异常处理、错误处理:error_reporting,try-catch,trigger_error,set_error_handler,set_exception_handler,register_shutdown_function
一.错误.异常 等级常量表 error:不能在编译期发现的运行期错误,比如试图用 echo 输出一个未赋值的变量,这类问题往往导致程序或逻辑无法继续下去而需要中断: exception:程序执行过程中 ...
- 【转】【整理】将Linux脚本中的正常输出,警告,错误等信息输出到文件中
本文来自:http://blog.csdn.net/woshinia/article/details/18040063 很早以前 编译的时候 就在用 2>&1,但是一直没有生成一 ...
- PHP错误处理及异常处理笔记
给新人总结一下PHP的错误处理. PHP提供了错误处理和日志记录的功能. 这些函数允许你定义自己的错误处理规则,以及修改错误记录的方式. 这样,你就可以根据自己的需要,来更改和加强错误输出信息以满足实 ...
- WCF之错误和异常
CLR异常无法跨越服务边界,所有的异常都被封装(序列化)为SOAP Fault,可以让所有平台的用户接收到. SOAP1.1只有Body.1.2中含有Header+Body. 未捕获异常 异常会从逻辑 ...
- 【转】正确理解PHP程序编译时的错误信息
我们编写程序时,无论怎样小心谨慎,犯错总是在所难免的.这些错误通常会迷惑PHP编译器.如果开发人员无法了解编译器报错信息的含义,那么这些错误信息不仅毫无用处,还会常常让人感到沮丧. 编译PHP脚本时, ...
- [译]JavaScript 错误和处理
JavaScript的调试是一个噩梦:一些错误刚开始很难理解,并且给出的错误函数也经常是没用的.如果把错误都列出来并给出解决办法会不会很有用呢. 下面列出了JavaScript一系列的奇怪错误.对于同 ...
随机推荐
- Docker使用:利用宝塔面板Docker管理器快速搭建PHP、Java、Python、nodejs等配套运行环境
思路:阿里云购买服务器选择centos7宝塔系统做宿主机,登录宝塔安装Docker管理器,获取一个centos7镜像,创建容器在里面再安装个宝塔后部署PHP.Python等. 点击购买阿里云云服务器, ...
- Qt/C++编写精美输入法(历时十年迭代/可换肤/支持Qt4/5/6/win/linux/mac/嵌入式等)
一.前言 大概是从2012年就开始研究用Qt写输入法,因为项目需要,嵌入式板子上,没有对应的输入法,当初使用过很多NVR,里面也是鼠标按下弹出输入法面板进行输入,可以切换数字和字母及中文,于是借鉴着操 ...
- Qt音视频开发01-共享解码线程(耗时一年/性能凶残/至臻完美)
一.前言 大概在8年前就开始用ffmpeg做视频解码的显示,第一个版本就100行代码左右,功能极其简单,就是开个线程解码视频流转成图片发给主界面绘制.时间过得真快,从当初的一胎到现在二胎都上学了三胎计 ...
- Android Studio4.1.2中,修改了gradle后,如何在不关闭AS IDE的情况下使gradle进行sync
Android Studio4.1.2中,修改了gradle后,如何在不关闭AS IDE的情况下使gradle进行sync: 方法1: 修改了gradle后,上面自然就弹出了一个提示框 你点击上面的S ...
- Win7/8/10操作系统之间通过“映射网络驱动器”映射共享目录或者网络磁盘,有的可以映射成功,有的不成功的原因和终极解决办法
Win7/8/10操作系统相互之间通过"映射网络驱动器"映射共享目录或者网络磁盘,有的可以映射成功,有的不成功 原因: 待添加映射驱动器的计算机的"网络发现"和 ...
- 一个R包—reticulate—在R中调用Python
R语言和python语言是生信行业经常使用的两个计算机语言,R语言具有统计和画图方面的优势,但是R语言在文件读写上的速度实在不敢恭维:Python具有较快的文件读写功能,但是其统计和画图却不如R语言用 ...
- Solution Set -「OurOJ Contest #2587」浅写
\(\mathscr A\sim\)「OurOJ #47030」_ Link & Submission & Tags:「A.DP-计数 DP」「A.数学-Stirling 数/反演 ...
- [docker逃逸] Privileged 特权模式逃逸复现
本文作者CVE-柠檬i CSDN:https://blog.csdn.net/weixin_49125123 博客园:https://www.cnblogs.com/CVE-Lemon 微信公众号:L ...
- 小程序之navigator跳转方式
navigator中的open-type可以决定小程序的跳转方式: 是否关闭当前页面 或者说以何种方式进行跳转 标签<navigator>中 open-type属性表示小程序的跳转方式: ...
- 五. Redis 配置内容(详细配置说明)
五. Redis 配置内容(详细配置说明) @ 目录 五. Redis 配置内容(详细配置说明) 1. Units 单位配置 2. INCLUDES (包含)配置 3. NETWORK (网络)配置 ...