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一系列的奇怪错误.对于同 ...
随机推荐
- Qt/C++音视频开发65-切换声卡/选择音频输出设备/播放到不同的声音设备/声卡下拉框
一.前言 近期收到一个用户需求,要求音视频组件能够切换声卡,首先要在vlc上实现,于是马不停蹄的研究起来,马上查阅对应vlc有没有自带的api接口,查看接口前,先打开vlc播放器,看下能不能切换,因为 ...
- UML之属性与参数的多重性
在UML中,多重性是指一个条目潜在的数量范围.多重性可被用于属性.操作参数.关联关系.UML元模型也使用多重性对元模型元素之间的关系进行约束.多重性总是包含基数值,它是相关条目在现实世界中的确切数量. ...
- 跟着源码学IM(十二):基于Netty打造一款高性能的IM即时通讯程序
本文由竹子爱熊猫分享,原题"(十一)Netty实战篇:基于Netty框架打造一款高性能的IM即时通讯程序",本文有修订和改动. 1.引言 关于Netty网络框架的内容,前面已经讲了 ...
- 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨
本文作者"商文默",本次有修订和改动. 1.写在前面 即时通讯网整理的大量IM技术文章中(见本文末"参考资料"一节),有关消息可靠性和一致性问题的文章占了很大比 ...
- Pytorch Utils 总结
Utils 从torch.nn.utils模块 clip_grad_norm_ 裁剪参数迭代的梯度范数. clip_grad_value_ 在指定值处剪辑可迭代参数的梯度. parameters_to ...
- linux输出文件名及全路径
有时候需要输出一个文件夹下的文件名及所以绝对路径,在网上找到是这个命令 ls | sed "s:^:`pwd`/:" 看命令不难理解,先是ls列出所有文件名,再使用管道符进行后续操 ...
- Solution Set -「NOIP Simu.」20221111
\(\mathscr{A}\sim\) 遗忘十字路 Cover:「CF 1746D」Paths on the Tree. Tag:「C.性质/结论」 最原始的思路自然是 DP. 令 \(f ...
- 【刷题】牛客模拟面试 > 模拟面试报告
https://www.nowcoder.com/interview/ai/index 1-TCP协议的流量控制和拥塞控制 TCP的流量控制是基于窗口机制实现的: 在建立连接时, 发送方和接收方都会建 ...
- ClickHouse-3引擎
引擎 数据库引擎 index 表引擎 数据库引擎 数据库引擎允许您处理数据表. 默认情况下,ClickHouse使用Atomic数据库引擎.它提供了可配置的table engines和SQL dial ...
- 原生JS实现一个日期选择器(DatePicker)组件
这是通过原生HTML/CSS/JavaScript完成一个日期选择器(datepicker)组件,一个纯手搓的组件的开发.主要包括datepicker静态结构的编写.日历数据的计划获取.组件的渲染以及 ...