GPool 是一个高效的 Go 语言协程池实现,旨在管理和重用 goroutine,以提高性能并控制并发。它特别适用于需要处理大量并发任务的应用程序,如 Web 服务器、数据处理管道或后台作业系统。
- 可控的并发度
- 自动任务队列管理
- 支持上下文取消
- 优雅的关闭机制
- 提供运行中任务数量的实时统计
在你的 Go 项目中使用以下命令安装 GPool:
go get github.com/sagoo-cloud/nexframe
import "github.com/sagoo-cloud/nexframe/os/gpool"
// 创建一个容量为 10 的协程池
pool := gpool.NewGPool(10)
GPool 提供两种方法来提交任务:Go
和 AddJob
。
Go
方法会尝试立即执行任务,如果池已满,则将任务加入队列。
pool.Go(func(ctx context.Context) error {
// 执行任务
return nil
})
AddJob
方法会将任务添加到队列中,如果队列已满,它会阻塞直到有空间可用。
pool.AddJob(func(ctx context.Context) error {
// 执行任务
return nil
})
使用 Wait
方法等待所有提交的任务完成:
pool.Wait()
使用 Shutdown
方法优雅地关闭池:
pool.Shutdown()
使用 RunningCount
方法获取当前正在运行的任务数:
count := pool.RunningCount()
fmt.Printf("当前运行的任务数:%d\n", count)
GPool 支持通过上下文来控制任务的生命周期:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
pool.Go(func(jobCtx context.Context) error {
select {
case <-jobCtx.Done():
fmt.Println("任务被取消")
return jobCtx.Err()
case <-time.After(3 * time.Second):
fmt.Println("任务完成")
return nil
}
})
任务函数可以返回错误,你应该在任务中妥善处理这些错误:
pool.Go(func(ctx context.Context) error {
// 模拟可能失败的操作
if rand.Float32() < 0.3 {
return errors.New("随机错误")
}
return nil
})
-
合理设置池容量:池容量应根据你的系统资源和预期负载来设置。
-
使用 defer 关闭池:在 main 函数或长期运行的程序中,使用 defer 确保池被正确关闭。
-
妥善处理错误:始终检查并处理任务返回的错误。
-
避免长时间运行的任务:将长时间运行的任务分解为较小的子任务,以提高池的整体吞吐量。
-
使用上下文控制任务生命周期:特别是对于可能需要取消的长时间运行任务。
以下是一个使用 GPool 的完整示例:
package main
import (
"context"
"fmt"
"log"
"math/rand"
"time"
"github.com/sagoo-cloud/nexframe/os/gpool"
)
func main() {
// 创建一个容量为 5 的协程池
pool := gpool.NewGPool(5)
defer pool.Shutdown()
// 创建一个带有超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// 提交 20 个任务
for i := 0; i < 20; i++ {
taskID := i
pool.Go(func(jobCtx context.Context) error {
// 模拟工作负载
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
select {
case <-jobCtx.Done():
fmt.Printf("任务 %d 被取消\n", taskID)
return jobCtx.Err()
default:
fmt.Printf("任务 %d 完成\n", taskID)
return nil
}
})
}
// 等待所有任务完成或上下文取消
<-ctx.Done()
// 等待池中的所有任务完成
pool.Wait()
fmt.Printf("总共运行的任务数:%d\n", pool.RunningCount())
}
- GPool 不保证任务的执行顺序。
- 如果池已满且工作队列也已满,
Go
方法会在新的 goroutine 中执行任务,这可能会暂时增加系统负载。 Shutdown
方法会等待所有任务完成,在此期间不应再提交新任务。
GPool 设计用于高并发场景,但实际性能可能因使用方式和系统资源而异。在生产环境中使用前,建议进行充分的性能测试和负载测试。
GPool 提供了一种简单而强大的方式来管理 Go 程序中的并发任务。通过合理使用 GPool,你可以有效控制程序的并发度,提高资源利用率,并简化错误处理和任务管理。