首页 > 编程语言 >golang流式编程

golang流式编程

时间:2022-12-01 09:33:40浏览次数:76  
标签:wg return err 编程 流式 golang func error type

https://blog.csdn.net/u012986012/article/details/126833564

 

 

借助一些设计模式、流式编程、函数编程的方法可以让我们的Golang代码更清晰优雅,本文中描述了在错误处理、可选配置、并发控制等方面的优化手段。图片

链式错误处理

很多人不喜欢Go的错误处理,需要写大量if err != nil的代码,特别是在一些复杂步骤场景中,每一步都要判断结果是否出错。在这种情况中,可以通过类似链式调用将错误封装在其中。

比如在对象中附带一个error属性,在每一步调用中如果error不为空直接返回

type Handler struct {
    props interface

    err error
}

func (h *Handler) Err() error {
    return h.err
}

func (h *Handler) Step1() *Handler {
    if h.err != nil {
        return h
    }

    // do something for step2
    return h
}

func (h *Handler) Step2() *Handler {
    if h.err != nil {
        return h
    }

    // do something fot step2
    return h
}

// ... StepN()

调用时直接通过链式调用即可,最后再判断错误

h := &Handler{}
if err := h.Step1().Step2().StepN().Err(); err != nil {
    // handle error
}

这种方式在一些数据库包中有大量使用,比如etcd、gorm。

可选配置

在创建对象时,如果可配置的属性很多,通常会引入一个配置文件

type Config struct {
    Port string
    Host string
    Timeout time.Time
    // ...
}
func NewServer(conf *Config) *Server {

}

通常这些配置都有默认值,config也不是必须的,通过建造者模式可以轻松解决此类问题

builder := &Builder{}
server := builder.WithPort("8080").WithHost("0.0.0.0").WithTimeOut(10*time.Second).Complete()

但建造者需要写一个建造类,配置对应的属性设置方法

type Builder struct {
    server Server
}

func (b *Builder) WithPort(port string) *Builder {
    b.server.port = port
    return b
}

func (b *Builder) WithHost(host string) *Builder {
    b.server.host = host
    return b
}

除了建造者模式,还可以通过可选配置,对调用者更友好,将配置项封装成Option,需要的时候注入对应的Option即可

type Option func(*Server)

type WithPort(port int) Option {
    return func(s *Server) {
        s.port = port
    }
}

type WithHost(host int) Option {
    return func(s *Server) {
        s.host = host
    }
}

type NewServer(opts ...Option) *Server {
    s := defaultServer() // 默认配置
    for _, opt := range opts {
        opt(s) // 添加可选配置
    }
    return s
}

调用时,只需在NewServer配置对应的Option即可

// 默认配置
s := NewServer()

// 可选配置
s := NewServer(WithPort("8080"), WithHost("127.0.0.1"))

可选配置相比直接使用配置和建造者模式,更加清晰,也非常容易扩展和维护,在kuberentes、etcd、go-redis库中都有非常多的应用。

并发控制

Golang基础库中已经提供不少并发控制工具,比如Channel、WaitGroup、各种锁等等。

ErrGroup、 WaitGroup可以等待多个Goroutine执行结束,但很多时候并发执行多个任务,如果其中一个任务出错那么整体失败,需要直接返回,这种情况下我们可以使用ErrGroup

ErrGroup借助封装了WaitGroup、Once以及Context,调用Wait时如果一个任务失败取消Context直接返回,核心逻辑如下

type ErrGroup struct {
 ctx    context.Context
 cancel func()

 wg sync.WaitGroup

 errOnce sync.Once
 err     error
}

func (g *ErrGroup) Wait() error {
 g.wg.Wait()

 if g.cancel != nil {
  g.cancel()
 }

 return g.err
}

func (g *ErrGroup) Go(f func(ctx context.Context) error) {
 g.wg.Add(1)

 go func() {
  defer g.wg.Done()
  if err := f(g.ctx); err != nil {
            // 执行失败则运行cancel
   g.errOnce.Do(func() {
    g.err = err
    if g.cancel != nil {
     g.cancel()
    }
   })
  }
 }()
}

控制并发数

借助有缓冲的Channel,可以实现控制Goroutine并发数,逻辑如下:

func NewCtrlGroup(number int) *CtrlGroup {
 return &CtrlGroup{
  ch: make(chan struct{}, number),
 }
}

type CtrlGroup struct {
 ch chan struct{}
 wg sync.WaitGroup
}

func (g *CtrlGroup) Enter() {
 g.ch <- struct{}{}
}

func (g *CtrlGroup) Leave() {
 <-g.ch
}

func (g *CtrlGroup) Go(f func()) {
 g.Enter() // 接收到新任务,发送到Channel,如果Channel满需要等待
 g.wg.Add(1)

 go func() {
  defer g.Leave() // 任务结束,取出一个元素
  defer g.wg.Done()
  f()
 }()
}

func (g *CtrlGroup) Wait() {
 g.wg.Wait()
}

总结

本文总结了Golang的一些有趣的编程模式,例如链式调用、可选配置、并发控制等,通过这些技巧或者手段,可以提高编码的质量。

原文:https://qingwave.github.io/golang-programming-pattern/#mapreduce

标签:wg,return,err,编程,流式,golang,func,error,type
From: https://www.cnblogs.com/cheyunhua/p/16940465.html

相关文章

  • Go-05 Golang中的运算符
    packagemainimport"fmt"/* Golang中的运算符 Golang内置的运算符: 1.算术运算符:+-*/% 2.关系运算符:!===>>=<<= 返回值是True或者False 3.逻辑运......
  • 实验四 Web服务器1-socket编程
    实验四Web服务器1-socket编程ipa查询网络状态echo服务器的客户端服务器,提交程序运行截图,服务器把客户端传进来的内容加入“服务器进程pid你的学号姓名echo:”......
  • Installing golang-1.18 on openEuler
    一、Installinggolang-1.18onopenEulerhttps://golang.google.cn1下载mkdir/opt/software&&cd/opt/softwarewgethttps://golang.google.cn/dl/go1.18.linux......
  • 计挑-C++-20-编程4
    题目描述有N个正整数,求这N个正整数两两之间的公共质因数之和。输入说明第1行:正整数N(N<100)第2行:N个空格分隔的正整数(每个元素<10000)输出说明输出这N个正整数两......
  • Golang实现小型CMS内容管理功能(二):前端接入百度ueditor富文本编辑器
    当我们把接口都做好以后,我们需要去开发前端界面。添加文章功能里面,最重要的就是文章内容部分,需要配置上富文本编辑器,这样才能给我们的内容增加样式。 下载ueditor代码......
  • 实验四 Web服务器1-socket编程
    任务详情基于华为鲲鹏云服务器CentOS中(或Ubuntu),使用LinuxSocket实现:time服务器的客户端服务器,提交程序运行截图echo服务器的客户端服务器,提交程序运行截图,服务器把客......
  • Flink-使用flink处理函数以及状态编程实现TopN案例
    7.5应用案例-TopN7.5.1使用ProcessAllWindowFunction场景例如,需要统计最近10秒内最热门的两个url链接,并且每5秒思路使用全窗口函数ProcessAllWindowFunction开......
  • 极客编程python入门-生成器
    generator通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。在Python中,这种一边循环一边计算的机制,称为生成器:generator。只要把一个列表生......
  • Golang-单元测试
    单元测试针对使用传统方式测试代码块的不足:1)测试代码块需要在main函数中去调用,需要修改main函数,若项目正在运行,就可能去停止项目,不方便2)不利于管理,当需要测试多个函数或多个......
  • 数据库编程——MongoDB json
    在学习数据库编程总结了笔记,并分享出来。有问题请及时联系博主:​​Alliswell_WP​​,转载请注明出处。09-数据库编程day05(mongodbjson)目录:一、学习目标二、复习三、作业四......