【译】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 ...
随机推荐
- VMware虚拟机性能优化
一.ESX及vCenter服务器的优化 检查ESX物理服务器是否在兼容列表中,特别是BIOS的版本是否符合ESX版本的要求 开启ESX物理服务器硬件虚拟化技术VT-X,AMD-V 关闭BIOS中的英特 ...
- 配置yum仓库的三种方法光盘镜像、nginx、sftp
方法一: 1.安装ftp服务 [root@oldboy ~]# yum -y install vsftpd 2.查看vsftpd相关的配置文件和目录 rpm -ql vsftpd # 查看vsftpd ...
- mysql数据库-简介
目录 1 MySQL 的三大主要分支 1.1 官方文档 1.2 版本演变 1.3 MySQL 安装方式 1.3.1 RPM包安装Mysql 1.3.2 二进制安装MySQL 1.4 mysql组成 1 ...
- 揭秘有状态服务上 Kubernetes 的核心技术
背景 随着 Kubernetes 成为云原生的最热门的解决方案,越来越多的传统服务从虚拟机.物理机迁移到 Kubernetes,各云厂商如腾讯自研上云也主推业务通过Kubernetes来部署服务,享受 ...
- Prometheus监控软件部署方法
背景:负责基于区块链的某公正项目的状态上报模块设计编码,基于Prometheus进行二次开发 1.说明Prometheus 是一个开源的服务监控软件,它通过 HTTP 协议从远程机器收集数据并存储在本 ...
- Django settings 描述
""" Django settings for log_collect_statistics project. Generated by 'django-admin st ...
- Nginx 配置实例-配置虚拟主机
Nginx 配置实例-配置虚拟主机 配置基于域名的虚拟主机 1. 配置域名为 aaa.domain.com 的虚拟主机 1.1 nginx 中虚拟主机的配置 1.2 相关目录及文件的创建 1.3 验证 ...
- Python+Selenium - 窗口切换
当有新窗口出现时,并要在新窗口操作,步骤: 1.产生新窗口 2.获取所有窗口的句柄:driver.window_handles 3.切换函数:driver.switch_to.window(新窗口句柄 ...
- HiCar基本功能介绍
HiCar基本功能介绍 基本概述 一方面,基于操作系统超强的分布式能力,HUAWEI HiCar通过手机和汽车之间的连接,基于三层标准与能力,构建手机和汽车互助资源池,把手机的服务生态延伸到车内,实现 ...
- 在NVIDIA-Jetson平台上构建智能多媒体服务器
在NVIDIA-Jetson平台上构建智能多媒体服务器 Building a Multi-Camera Media Server for AI Processing on the NVIDIA Jet ...