admin 发表于 2021-12-10 23:47:27

golang:使用信号量semaphore控制并发goroutine数量

■实例说明
虽然在go中创建协程代价很小,但过多但协程也会对系统造成压力,甚至会将服务拖垮。
使用信号量semaphore,可以三行代码就控制并发执行goroutine的数量。
1)信号量semaphore控制协程数量
2)默认每一个协程申请一个信号量,如果协程有不同等级,比如有的处理任务重,则可以多申请几个信号量,则可以根据协程处理任务的轻重情况,动态控制协程的数量

■实例代码

package main

import (
      "context"
      "fmt"
      "sync"
      "time"

      "golang.org/x/sync/semaphore"
)

// ControlGoRoutineCount 使用指定数量的协程处理某项工作
func ControlGoRoutineCount(goroutineCount int64) {
      weight := int64(1)

      // 创建信号量,一共只有goroutineCount个信号量可以申请,申请到了继续执行,申请不到需要等待
      sem := semaphore.NewWeighted(goroutineCount)
      wc := sync.WaitGroup{}

      // 这里比如需要执行1000次某个任务,我们是用goroutine去执行
      // 我们可以根据实际情况,替换这里的提交
      for t := 0; t < 1000; t++ {
                wc.Add(1)

                // 检查是否还有信号量,只有有的话才会继续创建协程,否则会在这里等待,直到有信号量被释放
                // 这里是申请1个信号量,如果这个任务重,可以根据实际情况申请多个信号量,相当于这里一个协程相当于其他几个协程
                sem.Acquire(context.Background(), weight)
                go func() {
                        defer func() {
                              wc.Done()
                              // 任务完成了,释放1个信号量
                              // 申请几个,释放几个
                              sem.Release(weight)
                        }()

                        // 这里执行自己的任务
                        // 这里使用sleep代替具体执行任务
                        time.Sleep(1 * time.Second)
                }()
      }
      wc.Wait()
}

// NoControlGoRoutineCount 不控制进程数量,直接使用协程处理任务
func NoControlGoRoutineCount() {
      wc := sync.WaitGroup{}
      for t := 0; t < 1000; t++ {
                wc.Add(1)

                go func() {
                        defer func() {
                              wc.Done()
                        }()

                        // 这里执行自己的任务
                        // 这里使用sleep代替具体执行任务
                        time.Sleep(1 * time.Second)
                }()
      }
      wc.Wait()
}

func main() {
      // 第一个方法控制只有200个协程可以执行,第二个方法不受控制,直接循环1000次,相当于有1000个协程同时执行
      // 所以控制协程数量的比不控制的慢了5倍的时间

      curTime := time.Now()
      // 控制只有100个协程处理某项工作
      ControlGoRoutineCount(200)
      fmt.Printf("ControlGoRoutineCount cost %d\n", time.Since(curTime))
      // 输出:ControlGoRoutineCount cost 5018998668

      curTime = time.Now()
      // 不控制协程数量,直接处理某项工作
      NoControlGoRoutineCount()
      fmt.Printf("NoControlGoRoutineCount cost %d\n", time.Since(curTime))
      // 输出:NoControlGoRoutineCount cost 1004587808
}

页: [1]
查看完整版本: golang:使用信号量semaphore控制并发goroutine数量