xgo

package
v0.7.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

README

XGo - 安全的 Go 协程池

XGo 是一个功能完整、安全可靠的 Go 协程池实现,提供了三种任务管理方式:基本任务提交、WaitGroup 批量管理和 ErrorGroup 错误收集。

核心特性

  • 🚀 高性能:基于 worker pool 模式,复用协程减少创建开销
  • 🛡️ Panic 安全:自动捕获和处理 panic,不会导致程序崩溃
  • 🎯 灵活控制:支持协程数量限制、动态扩缩容
  • 📦 批量管理:WaitGroup 支持批量任务等待
  • 错误收集:ErrorGroup 支持错误收集和快速失败
  • 🔄 上下文控制:完整的 context.Context 支持
  • 🔒 优雅关闭:支持优雅关闭和超时关闭

快速开始

基本使用
import "github.com/rushteam/beauty/pkg/xgo"

// 创建协程池
pool := xgo.New()
defer pool.Close()

// 提交任务
pool.Go(func() {
    fmt.Println("Hello, XGo!")
})
全局便捷函数
// 使用全局默认协程池
xgo.SafeGo(func() {
    fmt.Println("Safe goroutine")
})

三种任务管理方式

1. 基本任务提交 - Go()

适用于简单的 fire-and-forget 任务:

pool := xgo.New()
defer pool.Close()

pool.Go(func() {
    // 执行任务
    fmt.Println("Task completed")
})
2. WaitGroup - 批量任务管理

适用于需要等待一组任务完成的场景:

pool := xgo.New()
defer pool.Close()

wg := pool.NewWaitGroup()

// 提交多个任务
for i := 0; i < 10; i++ {
    taskID := i
    wg.Go(func() {
        fmt.Printf("Task %d completed\n", taskID)
    })
}

// 等待所有任务完成
wg.Wait()
fmt.Println("All tasks completed")
3. ErrorGroup - 错误收集和快速失败

适用于需要收集错误或快速失败的场景:

pool := xgo.New()
defer pool.Close()

eg := pool.NewErrorGroup()

// 提交可能失败的任务
eg.Go(func() error {
    // 业务逻辑
    if someCondition {
        return fmt.Errorf("task failed")
    }
    return nil
})

// 等待并获取第一个错误
if err := eg.Wait(); err != nil {
    fmt.Printf("Error occurred: %v\n", err)
}

高级功能

上下文控制
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

wg := pool.NewWaitGroup()
wg.GoWithContext(ctx, func(ctx context.Context) {
    select {
    case <-ctx.Done():
        fmt.Println("Task cancelled")
        return
    default:
        // 执行任务
    }
})
wg.Wait()
ErrorGroup 快速失败
eg, ctx := pool.NewErrorGroupWithContext(context.Background())

// 当任何任务失败时,其他任务会被自动取消
eg.Go(func() error {
    return fmt.Errorf("critical error") // 触发快速失败
})

eg.GoWithContext(ctx, func(ctx context.Context) error {
    select {
    case <-ctx.Done():
        return ctx.Err() // 被取消
    default:
        // 正常执行
        return nil
    }
})

err := eg.Wait() // 返回第一个错误
自定义配置
pool := xgo.New(
    xgo.WithSetCap(100),                    // 最大 100 个 worker
    xgo.WithScaleThreshold(5),              // 当待处理任务 >= 5 时创建新 worker
    xgo.WithPanicHandler(func(taskName string, panicValue any, stack []byte) {
        // 自定义 panic 处理
        log.Printf("Panic in task [%s]: %v\n%s", taskName, panicValue, stack)
    }),
)
defer pool.Close()

实际应用场景

批量数据处理
func ProcessUsers(users []User) error {
    pool := xgo.New(xgo.WithSetCap(20))
    defer pool.Close()
    
    wg := pool.NewWaitGroup()
    
    for _, user := range users {
        user := user
        wg.Go(func() {
            processUser(user)
        })
    }
    
    wg.Wait()
    return nil
}
批量 API 调用
func CallAPIs(urls []string) error {
    eg := xgo.NewErrorGroup()
    
    for _, url := range urls {
        url := url
        eg.Go(func() error {
            resp, err := http.Get(url)
            if err != nil {
                return err
            }
            defer resp.Body.Close()
            
            if resp.StatusCode != 200 {
                return fmt.Errorf("HTTP %d: %s", resp.StatusCode, url)
            }
            return nil
        })
    }
    
    return eg.Wait() // 返回第一个错误
}
微服务并发调用
func CallServices(ctx context.Context) error {
    eg, ctx := xgo.NewErrorGroupWithContext(ctx)
    
    eg.GoWithContext(ctx, func(ctx context.Context) error {
        return callUserService(ctx)
    })
    
    eg.GoWithContext(ctx, func(ctx context.Context) error {
        return callOrderService(ctx)
    })
    
    return eg.Wait() // 任何服务失败都会快速返回
}

API 参考

Pool 接口
type Pool interface {
    Go(f func())
    GoWithContext(ctx context.Context, f func(ctx context.Context))
    NewWaitGroup() *WaitGroup
    NewErrorGroup() *ErrorGroup
    NewErrorGroupWithContext(ctx context.Context) (*ErrorGroup, context.Context)
    Workers() int32
    PendingTasks() int
    Close() error
    CloseWithTimeout(timeout time.Duration) error
}
WaitGroup 方法
func (w *WaitGroup) Go(f func())
func (w *WaitGroup) GoWithContext(ctx context.Context, f func(ctx context.Context))
func (w *WaitGroup) Wait()
func (w *WaitGroup) Add(delta int)    // 高级用法
func (w *WaitGroup) Done()            // 高级用法
ErrorGroup 方法
func (eg *ErrorGroup) Go(f func() error)
func (eg *ErrorGroup) GoWithContext(ctx context.Context, f func(ctx context.Context) error)
func (eg *ErrorGroup) Wait() error
func (eg *ErrorGroup) Context() context.Context
全局函数
func SafeGo(f func())
func SafeGoWithContext(ctx context.Context, f func(ctx context.Context))
func NewWaitGroup() *WaitGroup
func NewErrorGroup() *ErrorGroup
func NewErrorGroupWithContext(ctx context.Context) (*ErrorGroup, context.Context)

配置选项

func WithSetCap(cap int32) Option                    // 设置最大 worker 数量
func WithScaleThreshold(threshold int) Option        // 设置扩容阈值
func WithPanicHandler(f func(string, any, []byte)) Option  // 设置 panic 处理函数

最佳实践

  1. 选择合适的模式

    • 简单任务用 Go()
    • 需要等待的批量任务用 WaitGroup
    • 需要错误处理的任务用 ErrorGroup
  2. 合理设置参数

    • WithSetCap() 建议设置为 CPU 核数的 2-10 倍
    • WithScaleThreshold() 建议设置为 2-5
  3. 资源管理

    • 总是调用 defer pool.Close() 确保资源释放
    • 对于长期运行的服务,考虑使用全局协程池
  4. 错误处理

    • 使用 ErrorGroup 处理可能失败的批量任务
    • 自定义 PanicHandler 进行错误监控和告警

性能特点

  • 内存效率:复用协程,减少创建/销毁开销
  • 调度优化:控制并发数量,减少调度器压力
  • 资源可控:支持最大协程数限制,防止资源耗尽
  • 快速失败:ErrorGroup 支持快速失败,减少资源浪费

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func SafeGo

func SafeGo(f func())

SafeGo 使用默认协程池安全执行协程

func SafeGoWithContext

func SafeGoWithContext(ctx context.Context, f func(ctx context.Context))

SafeGoWithContext 使用默认协程池安全执行带上下文的协程

Types

type ErrorGroup

type ErrorGroup struct {
	// contains filtered or unexported fields
}

ErrorGroup 协程池的错误组,提供错误收集和快速失败能力

func NewErrorGroup

func NewErrorGroup() *ErrorGroup

NewErrorGroup 使用默认协程池创建 ErrorGroup

Example

示例:全局 ErrorGroup

// 使用全局默认协程池
eg := NewErrorGroup()

// 模拟批量处理,其中一个失败
eg.Go(func() error {
	return nil // 成功
})

eg.Go(func() error {
	return fmt.Errorf("处理失败")
})

// 等待所有任务完成
if err := eg.Wait(); err != nil {
	fmt.Printf("批量处理失败: %v\n", err)
} else {
	fmt.Println("所有处理成功")
}
Output:
批量处理失败: 处理失败

func NewErrorGroupWithContext

func NewErrorGroupWithContext(ctx context.Context) (*ErrorGroup, context.Context)

NewErrorGroupWithContext 使用默认协程池创建带上下文的 ErrorGroup

func (*ErrorGroup) Context

func (eg *ErrorGroup) Context() context.Context

Context 返回 ErrorGroup 的上下文

func (*ErrorGroup) Go

func (eg *ErrorGroup) Go(f func() error)

Go 提交任务到协程池并加入错误组

func (*ErrorGroup) GoWithContext

func (eg *ErrorGroup) GoWithContext(ctx context.Context, f func(ctx context.Context) error)

GoWithContext 提交带上下文的任务到协程池并加入错误组

func (*ErrorGroup) Wait

func (eg *ErrorGroup) Wait() error

Wait 等待所有任务完成并返回第一个错误

type Option

type Option func(p *wokerpool)

func WithPanicHandler

func WithPanicHandler(f func(taskName string, panicValue any, stack []byte)) Option

WithPanicHandler 设置 panic 处理函数

Example

示例:自定义 panic 处理

pool := New(WithPanicHandler(func(taskName string, panicValue any, stack []byte) {
	// 这里可以记录日志、发送告警等
	// 为了示例输出的一致性,这里不打印 panic 信息
}))
defer pool.Close()

wg := pool.NewWaitGroup()
wg.Go(func() {
	panic("模拟错误")
})

wg.Wait()
fmt.Println("即使发生 panic,程序仍然继续运行")
Output:
即使发生 panic,程序仍然继续运行

func WithScaleThreshold

func WithScaleThreshold(threshold int) Option

WithScaleThreshold 设置扩容阈值

func WithSetCap

func WithSetCap(cap int32) Option

type Pool

type Pool interface {
	// Go 提交一个任务到协程池执行
	Go(f func())
	// GoWithContext 提交带上下文的任务
	GoWithContext(ctx context.Context, f func(ctx context.Context))
	// NewWaitGroup 创建一个新的 WaitGroup,用于批量任务管理
	NewWaitGroup() *WaitGroup
	// NewErrorGroup 创建一个新的 ErrorGroup,用于错误收集和快速失败
	NewErrorGroup() *ErrorGroup
	// NewErrorGroupWithContext 创建带上下文的 ErrorGroup
	NewErrorGroupWithContext(ctx context.Context) (*ErrorGroup, context.Context)
	// Workers 返回当前活跃的 worker 数量
	Workers() int32
	// PendingTasks 返回待处理的任务数量
	PendingTasks() int
	// Close 优雅关闭协程池,等待所有任务完成
	Close() error
	// CloseWithTimeout 带超时的关闭协程池
	CloseWithTimeout(timeout time.Duration) error
}

Pool 协程池接口,提供安全的协程执行能力

func New

func New(opts ...Option) Pool
Example

示例:协程池配置

pool := New(
	WithSetCap(10),        // 最大 10 个 worker
	WithScaleThreshold(3), // 当待处理任务 >= 3 时创建新 worker
)
defer pool.Close()

fmt.Println("协程池创建成功")
Output:
协程池创建成功

type Task

type Task struct {
	// contains filtered or unexported fields
}

Task 任务结构体

type WaitGroup

type WaitGroup struct {
	// contains filtered or unexported fields
}

WaitGroup 协程池的等待组,提供批量任务管理能力

func NewWaitGroup

func NewWaitGroup() *WaitGroup

NewWaitGroup 使用默认协程池创建 WaitGroup

Example

示例:全局便捷函数

// 使用全局默认协程池创建 WaitGroup
wg := NewWaitGroup()

// 提交任务
wg.Go(func() {
	fmt.Println("全局任务 1")
})

wg.Go(func() {
	fmt.Println("全局任务 2")
})

// 等待完成
wg.Wait()
fmt.Println("全局任务完成")

func (*WaitGroup) Add

func (w *WaitGroup) Add(delta int)

Add 手动增加等待计数(高级用法)

func (*WaitGroup) Done

func (w *WaitGroup) Done()

Done 手动减少等待计数(高级用法)

func (*WaitGroup) Go

func (w *WaitGroup) Go(f func())

Go 提交任务到协程池并加入等待组

func (*WaitGroup) GoWithContext

func (w *WaitGroup) GoWithContext(ctx context.Context, f func(ctx context.Context))

GoWithContext 提交带上下文的任务到协程池并加入等待组

Example

示例:带上下文的任务控制

pool := New()
defer pool.Close()

// 创建带超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

wg := pool.NewWaitGroup()
wg.GoWithContext(ctx, func(ctx context.Context) {
	select {
	case <-ctx.Done():
		fmt.Println("任务被取消:", ctx.Err())
	case <-time.After(time.Millisecond * 100):
		fmt.Println("任务完成")
	}
})

wg.Wait()
Output:
任务被取消: context deadline exceeded

func (*WaitGroup) Wait

func (w *WaitGroup) Wait()

Wait 等待所有任务完成

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL