go多函数并发通用工具的设计与实现

看源码时出现此情此景,如出至宝,由此记录!

目录

可应用场景

代码设计

使用


可应用场景

多个函数并发执行各自功能的使用,每一个函数就是开启协程执行的一个单元,每个函数中即可进行如复杂网络请求等可支持并发的需求。例如你的项目中某接口中需要执行三个函数,这三个函数都是向指定库执行插入操作且顺序无关,函数返回error,这三个函数即可并发进行,就可用这个设计。

代码设计

自定义错误接口,错误类型转换、及并发的开启,入参有多少个函数,将开启多少个协程,每个函数出现的错误将由通道统一写入切片并返回。

import (
	"errors"
	"fmt"
	"os"
)

type ErrorInterface interface {
	error
	Errors() []error
}

type agghelper []error

func (agg agghelper) Error() string {
	if len(agg) == 0 {
		return ""
	}
	if len(agg) == 1 {
		return agg[0].Error()
	}
	result := fmt.Sprintf("[%s", agg[0].Error())
	for i := 1; i < len(agg); i++ {
		result += fmt.Sprintf(", %s", agg[i].Error())
	}
	result += "]"
	return result
}

func (agg agghelper) Errors() []error {
	return []error(agg)
}

func NewAggHelper(errlist []error) ErrorInterface {
	if len(errlist) == 0 {
		return nil
	}
	var errs []error
	for _, e := range errlist {
		if e != nil {
			errs = append(errs, e)
		}
	}
	if len(errs) == 0 {
		return nil
	}
	return agghelper(errs)    //转换类型
}

//如果所有函数均成功完成,则返回nil
func ParallelGoroutines(funcs ...func() error) ErrorInterface {
	errChan := make(chan error, len(funcs))
	for _, f := range funcs {
		go func(f func() error) {
			// 若函数需要返回数据,则进行相应改造即可,可直接用interface{}
			// 或可自定义结构体到chan中, 结构体中组合包括错误在内的多个类型, 与f的返回类型对应即可
			errChan <- f()
		}(f)
	}
	errs := make([]error, 0)
	for i := 0; i < cap(errChan); i++ {
		if err := <-errChan; err != nil {
			errs = append(errs, err)
		}
	}
	// 若函数需要返回包括错误在内的多个值,可进行相应改造
	return NewAggHelper(errs)
}

使用

用文件写入操作测试如下:

addContent函数用来进行多函数的并发,writeTo用来实现具体的写文件操作

const (
	file1Name = "./error/t1.txt"
	file2Name = "./error/t2.txt"
)

func writeTo(fileName, content string) error {
	dstFile, err := os.Create(fileName)
	// 制造错误,如果有错误,将把错误处理成一个切片
	//if fileName == file1Name {
		err = errors.New("人造错误")		//错误切片:[人造错误, 人造错误]
	//}

	if err != nil {
		fmt.Println("写入报错:", err.Error())
		return err
	}
	defer dstFile.Close()
	dstFile.WriteString(content + "\n")
	fmt.Println("写入完成:", fileName)
	return nil
}

func addContent(content string) error {
	// 这里放两个函数各自执行各自的写入操作
	return ParallelGoroutines(
		// 1
		func() error {
			return writeTo(file1Name, content)
		},
		// 2
		func() error {
			return writeTo(file2Name, content)
		},
		//	Your more func...
	)
}

// 使用
func main() {
	err := addContent("hello")
	fmt.Println("报错:", err)
}

没有产生错误和产生错误的情况结果分别如下:

写入完成: ./error/t2.txt
写入完成: ./error/t1.txt
报错: <nil>


写入报错: 人造错误
写入报错: 人造错误
报错: [人造错误, 人造错误]

如果你的每个函数执行返回结果类型不只是error则只需进行相应改造即可,改造办法也很多,代码中进行了说明。

二十四桥仍在,波心荡冷月无声。

发布了155 篇原创文章 · 获赞 74 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/HYZX_9987/article/details/103298105
今日推荐