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组合使用