优雅的控制协程(goroutine)的并发数量

对golang熟悉的小伙伴都知道,在go中开启go协程是一件简单的事,只需要一个关键字”go“。

并且相比于线程,所需要的系统资源非常少。于是在程序中我们总会开启协程去并发获取数据。

例如:

商城首页,每个商品需要获取图片、价格、销量、店铺、优惠等等一系列信息。

如果单个单个的请求,肯定会由于响应太慢,流失用户。

于是我们自然的会想到使用并发去获取数据,组装后在返回给前端展示。

不过在微服务中,一般信息不会都存在自己这里,会有下游服务进行提供,为了保护自己的系统不会被高流量打垮,下游一般都会限制请求的qps。

比如你有50个商品,但是下游限制10个并发。那么我们就需要一种控制并发数量的手段去请求下游。

在golang中,channel 和 waitgroup 就是常用的控制并发请求的手段。下面我们就来实现一个通用的并发控制方法。

//定义通用函数,包装用户的业务函数,返回单次执行的result和error
type fcWarp func(interface{
   }) (interface{
   }, error)


/**
   goNum := 一共需要开启的协程数
   data  := 业务请求参数,必须是slice
   fc:定义通用函数,包装用户的业务函数,返回单次执行的result和error
   返回:
   result:slice类型,包含多次请求的结果
   resErrs :slice类型,包含多次请求中出现的err
 */
func concurrent(goNum uint, data interface{
   }, fc fcWarp)(result []interface{
   },resErrs []error) {
   
	if goNum <= 0 {
   
		panic("goNum must positive")
	}
	vType := reflect.TypeOf(data)
	if vType.Kind() != reflect.Slice{
   
		panic("data must slice")
	}
	vValue := reflect.ValueOf(data)

	limiter := make(chan struct{
   },goNum)
	result = make([]interface{
   },vValue.Len())
	resErrs = make([]error,vValue.Len())

	var wg sync.WaitGroup
	wg.Add(vValue.Len())
	for i := 0; i < vValue.Len(); i++ {
   
		limiter <- struct{
   }{
   }
		go func(i int,d interface{
   }) {
   
			defer func() {
   
				<-limiter
				wg.Done()
				if err := recover();err != nil{
   
					resErrs[i] = fmt.Errorf("panic:%v",err)
				}
			}()
			res,err := fc(d)
			result[i] = res
			resErrs[i] = err
		}(i,vValue.Index(i).Interface())
	}
	wg.Wait()
	return result, resErrs
}

实际使用效果:

整体使用非常简单,只需要进行简单的断言就可以转化为原始数据进行处理。

并且可以通过下标获取到每次的请求res 和 err。

不需要去关心协程控制、错误处理

func main()  {
   
	data := []int{
   1,2,3}
	res,errs := concurrent(2,data, func(idata interface{
   }) (interface{
   }, error) {
   
		tmp := idata.(int)
		if tmp == 2 {
   
			panic("is 2")
		}
		tmp += tmp
		return tmp,nil
	})

	for i := 0; i < len(data); i++ {
   
		if errs[i] != nil{
   
			fmt.Println(errs[i])
			continue
		}
		fmt.Println(res[i])
	}
}

输出:

2
panic:is 2
6

推荐阅读

1、原来阿里字节员工简历长这样

2、一条SQL差点引发离职

3、MySQL并发插入导致死锁


如果你也觉得我的分享有价值,记得点赞或者收藏哦!你的鼓励与支持,会让我更有动力写出更好的文章哦!

相关推荐

  1. 优雅控制(goroutine)并发数量

    2024-01-26 11:24:03       51 阅读
  2. golang大杀器goroutine

    2024-01-26 11:24:03       64 阅读
  3. Golang并发编程-goroutine初体验

    2024-01-26 11:24:03       34 阅读
  4. golanggoroutine教程

    2024-01-26 11:24:03       52 阅读
  5. 【go从入门到精通】精通并发编程-goroutine

    2024-01-26 11:24:03       28 阅读
  6. FREERTOS

    2024-01-26 11:24:03       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-26 11:24:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-26 11:24:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-26 11:24:03       82 阅读
  4. Python语言-面向对象

    2024-01-26 11:24:03       91 阅读

热门阅读

  1. Scikit-Learn 高级教程——自定义评估器

    2024-01-26 11:24:03       54 阅读
  2. JWT登录

    JWT登录

    2024-01-26 11:24:03      57 阅读
  3. CKA考试练习题

    2024-01-26 11:24:03       50 阅读
  4. P1065 [NOIP2006 提高组] 作业调度方案题目

    2024-01-26 11:24:03       49 阅读
  5. ssh: connect to host github.com port 22: Connection refused

    2024-01-26 11:24:03       47 阅读
  6. Spring---@Import注解

    2024-01-26 11:24:03       47 阅读
  7. Html转义字符及其对应的实体名称

    2024-01-26 11:24:03       43 阅读