使用Go语言实现一个优雅的协程池
协程池主要用到channel和goroutine来实现,以下是构思过程:
- 首先,通过channel来作为任务队列,让worker从中获取任务执行,避免创建过多的goroutine,减少资源消耗。
- 然后,使用协程池来处理这些任务。
这样可以有效均摊协程的压力,以及合理的调配这些任务。
以下是通过使用协程池和不使用做了一个比较,这是代码实现。
package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
const (
taskNums = 100
gNums = 10
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
ch := 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))
// case
singleThreadedStart := 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")
return
case 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输出部分省略)