go-zero-workergroup

224 阅读1分钟

worker group 诞生的背景

goroutine 太多仍会导致调度性能下降、GC 频繁、内存暴涨, 引发一系列问题。在面临这样的场景时, 限制 goroutine 的数量、重用 goroutine 显然很有价值

实现

主要是用chan来控制goruntine的数量

// A TaskRunner is used to control the concurrency of goroutines.
type TaskRunner struct {
   limitChan chan lang.PlaceholderType
}

lang.PlaceholderType 是 struct{}的别名

构造方法

// NewTaskRunner returns a TaskRunner.
func NewTaskRunner(concurrency int) *TaskRunner {
   return &TaskRunner{
      limitChan: make(chan lang.PlaceholderType, concurrency),
   }
}

执行

// Schedule schedules a task to run under concurrency control.
func (rp *TaskRunner) Schedule(task func()) {
   rp.limitChan <- lang.Placeholder

   go func() {
      defer rescue.Recover(func() {
         <-rp.limitChan
      })

      task()
   }()
}

执行过程中可能发生的panic需要recover住

用法

func TestRoutinePool(t *testing.T) {
   times := 100
   pool := NewTaskRunner(runtime.NumCPU())

   var counter int32
   var waitGroup sync.WaitGroup
   for i := 0; i < times; i++ {
      waitGroup.Add(1)
      pool.Schedule(func() {
         atomic.AddInt32(&counter, 1)
         waitGroup.Done()
      })
   }

   waitGroup.Wait()

   assert.Equal(t, times, int(counter))
}

一般和sync.WaitGroup组合使用

go-zero 源码

github.com/zeromicro/g…