使用Go语言实现一个优雅的协程池
协程池主要用到channel和goroutine来实现,以下是构思过程:
- 首先,通过channel来作为任务队列,让worker从中获取任务执行,避免创建过多的goroutine,减少资源消耗。
- 然后,使用协程池来处理这些任务。
这样可以有效均摊协程的压力,以及合理的调配这些任务。
以下是通过使用协程池和不使用做了一个比较,这是代码实现。
package mainimport ("context""fmt""sync""time"
)func main() {const (taskNums = 100gNums = 10)ctx, cancel := context.WithCancel(context.Background())defer cancel()var wg sync.WaitGroupch := make(chan int, 10)start := time.Now()for i := 0; i < gNums; i++ {wg.Add(1)go worker(ctx, i, ch, executeFunc, &wg)}for i := 1; i <= taskNums; i++ {ch <- i}close(ch)wg.Wait()fmt.Println(time.Since(start))// casesingleThreadedStart := time.Now()for i := 1; i <= taskNums; i++ {executeFunc(-1, i)}fmt.Println(time.Since(singleThreadedStart))
}func worker(ctx context.Context, id int, ch chan int, f func(int, any), wg *sync.WaitGroup) {defer wg.Done()for {select {case <-ctx.Done():fmt.Println("stop")returncase task, ok := <-ch:if !ok {return}f(id, task)//time.Sleep(time.Second * 1)}}
}func executeFunc(id int, task any) {fmt.Println("g_id:", id, "task:", task.(int))
}
测试结果:
531.9µs
18.2275ms
(fmt输出部分省略)