【译】GO语言:管理多个错误
原文:https://medium.com/a-journey-with-go/go-multiple-errors-management-a67477628cf1
关于开发者使用Go遇到的最大挑战的年度调查报告中,错误管理是经常被争论和反复提起的话题。然而,当涉及到在并发环境中处理错误或为相同的 goroutine 组合多个错误时,Go 提供了很好的包,使多个错误的管理变得很容易
单个 goroutine,多个错误
例如,当您处理具有重试策略的代码时,将多个错误合并成一个非常有用。下面是一个基本的例子,其中我们需要收集生成的错误:
var data = []byte(
`a,b,c
foo
1,2,3
,",
`)
func main() {
reader := csv.NewReader(bytes.NewBuffer(data))
for {
if _, err := reader.Read(); err != nil {
if err == io.EOF {
break
}
log.Printf(err.Error())
}
}
}
上面的程序读取、解析一个 CSV 文件,并且显示报错信息。它可以更方便的对错误进行分组以获得完整的报告。为了将错误合并成一个,我们需要在两个很优秀的包中选择一个:
使用 HashiCorp 的
go-multierror,可以将错误合并为一个标准错误func main() {
var errs error
reader := csv.NewReader(bytes.NewBuffer(data))
for {
if _, err := reader.Read(); err != nil {
if err == io.EOF {
break
}
errs = multierror.Append(errs, err)
}
}
if errs != nil {
log.Printf(errs.Error())
}
}
接着错误报告可以被打印出来

使用 Uber 的
multierr代码的实现是类似的,下面是输出

错误通过分号连接,没有任何其他格式。
关于每个包的性能,下面是一个具有较高失败次数的程序的基准测试
name time/op alloc/op allocs/op
HashiCorpMultiErrors-4 6.01µs ± 1% 6.78kB ± 0% 77.0 ± 0%
UberMultiErrors-4 9.26µs ± 1% 10.3kB ± 0% 126 ± 0%
Uber 的速度稍慢,占用内存更多。但是,这个包的设计目的是在收集到错误之后将其分组,而不是每次都添加错误。当对错误进行分组时,结果很接近,但是代码不够优雅,因为它需要额外的步骤。以下是新的测试结果:
name time/op alloc/op allocs/op
HashiCorpMultiErrors-4 6.01µs ± 1% 6.78kB ± 0% 77.0 ± 0%
UberMultiErrors-4 6.02µs ± 1% 7.06kB ± 0% 77.0 ± 0%这两个包都利用了 Go 错误接口,它们都实现了自己的
Error() string函数。
一个错误, 多个 goroutines
当多个 goroutine 来处理一个任务时,正确管理结果和聚合错误以确保程序的正确性是必要的。
让我们从一个使用多个 goroutine 执行一系列操作的程序开始,每一个操作都持续一秒:
func main() {
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
defer wg.Done()
if err := action(); err != nil {
return
}
if err := action(); err != nil {
return
}
if err := action(); err != nil {
return
}
}()
}
wg.Wait()
}
为了解释错误的传播,第三个 goroutine 的第一个操作会失败,下面时正在发生的事情:

正如预期的那样,程序大约需要 3 秒钟,因为大多数 goroutine 需要经历三个操作,每个操作花费一秒:
go run . 0.30s user 0.19s system 14% cpu 3.274 total
然而,我们可能希望让这些 goroutine 互相依赖,并在其中一个失败时取消它们以避免不必要的工作,解决方案是添加一个上下文,一旦 goroutine 失败,它就会取消它。

这个功能这是 errgroup 包所提供的;当一组 goroutine 工作时的错误和上下文传播。
下面时使用 errgroup包的代码:
func main() {
g, ctx := errgroup.WithContext(context.Background())
for i := 0; i < 4; i++ {
g.Go(func () error {
if err := action(ctx); err != nil {
return err
}
if err := action(ctx); err != nil {
return err
}
if err := action(ctx); err != nil {
return err
}
return nil
})
}
if err := g.Wait(); err != nil {
log.Printf(err.Error())
}
}
现在程序运行的更快了,因为它在发生错误时传播了取消上下文:
go run . 0.30s user 0.19s system 38% cpu 1.269 total
该包提供的另一个好处是,我们不再需要担心 goroutine 的添加和对 goroutine 标记完成。包替我们管理这些, 我们只需要等待程序完成并结束。
【译】GO语言:管理多个错误的更多相关文章
- Module Zero之语言管理
返回<Module Zero学习目录> 概览介绍 如何开启 管理语言 管理本地化文本 概览介绍 ABP定义了一个健壮的UI本地化系统,它可用于服务端和客户端.它允许在不同的资源中(Reso ...
- C#管理异常和错误
C#管理异常和错误 1.try/catch捕捉异常的语句块,其中try{}中是写可能会出错的程序代码,catch{}中是抛出异常的代码:一个try后可以有多个catch. 2.异常采用继承层次结构进行 ...
- C语言学习008:标准错误
在上一节中的数据文件中(C语言学习007:重定向标准输入和输出),如果文件中的数据包含非法数据,如何让程序显示一条错误的提示消息呢?就需要用到标准错误 #include <stdio.h> ...
- 解决Linux c语言运行时候“段错误 (核心已转储)”问题-采用gdb 解决
编译没有警告,没有错误,运行就打印 段错误 (核心已转储) 网上找了一下,都是各种问题,都推荐用gdb 调试解决,咱也来趁机学习gdb一下. gcc+gdb)输入命令行 运行 sudo apt-g ...
- 使用Jena RDF API 开发脚本语言管理资源描述框架模型
摘要 资源描述框架(Resource Description Framework RDF)是一种以XML格式描述元数据的标准格式.Jena是一种用于将关系数据库或是文本文件中所表示的数据建立为元数据模 ...
- Swift5 语言指南(十九) 错误处理
错误处理是响应程序中的错误条件并从中恢复的过程.Swift为在运行时抛出,捕获,传播和操纵可恢复的错误提供了一流的支持. 某些操作无法保证始终完成执行或生成有用的输出.Optionals用于表示缺少值 ...
- [译]Unity3D内存管理——对象池(Object Pool)
原文地址:C# Memory Management for Unity Developers (part 3 of 3), 其实从原文标题可以看出,这是一系列文章中的第三篇,前两篇讲解了从C#语言本身 ...
- (c语言编程)出现错误:null undeclared identifier
原因:没有添加头文件#include <stdio.h> 添加完头文件后,错误消失
- [译]C#控制管理VisualSVN Server
VisualSVN Server可以用WMI接口管理(Windows Management Instrumentation). VisualSVN Server安装的计算机中,位于%VISUALSVN ...
随机推荐
- Linux进阶之LAMP和LNMP动态网站搭建
一.什么是LAMP LAMP=Linux Apache Mysql/MariaDB PHP/Perl/Python 这些软件都是开源免费的软件,几个程序各自是独立的,经常为了达到我们需要的效果而协同工 ...
- STM32独立看门狗(IWDG)
造成程序跑飞,只是程序的正常运行状态被打断而进入死循环,从而使单片机控制的系统无法正常工作.看门狗就是一种专门用于检测单片机程序运行状态的硬件结构. STM32内部自带了两个看门狗,独立看门狗(IWD ...
- BXL文件怎样转换为AD LIB文件
https://jingyan.baidu.com/article/48b558e326e1b17f39c09a57.html
- 【错误解决】Error creating bean with name 'transactionManager' :nested exception is java.lang.NoClassDefFoundError: org/springframework/jdbc/datasource/
搭建ssh框架中新建JUint测试出现的问题.这个问题实在太伤脑筋....因为不好找到解决办法 直接先说解决方式:添加org.springframework.jdbc-XX.jar,然后build p ...
- 抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext
长话短说,本文带大家抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext 引言 C#异步编程语法糖async/await,使开发者很容易就能编写异步代码. ...
- Java反射机制 之 获取类的 方法 和 属性(包括构造函数)(Day_06)
把自己立成帆,才能招来凤. 运行环境 JDK8 + IntelliJ IDEA 2018.3 本文中使用的jar包链接 https://files.cnblogs.com/files/papercy ...
- Cisco Catalyst 9800-CL Wireless Controller for Cloud
面向云的思科 Catalyst 9800-CL 无线控制器,专为基于意图的网络全新打造. 版本: C9800-CL-universalk9.17.04.01 (29-Nov-2020) C9800-C ...
- 死磕nginx系列
死磕nginx系列 死磕nginx系列--nginx入门 死磕nginx系列--nginx配置文件 死磕nginx系统--nginx日志配置 死磕nginx系列--nginx服务器做web服务器 死磕 ...
- Windows家庭版打开或关闭Hyper-V
打开hyper-v 创建open_hyper-v.bat文件 pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper ...
- 在cuDNN中简化Tensor Ops
在cuDNN中简化Tensor Ops 在Tesla V100 GPU中引入神经网络模型以来,神经网络模型已迅速利用NVIDIA Tensor Cores进行深度学习.例如,基于Tensor Core ...