golang多协程执行控制与返回策略管理插件库hands的使用
Golang多协程执行控制与返回策略管理插件库hands的使用
Hands简介
Hands是一个用于控制多个goroutine执行和返回策略的进程控制器。
快速开始
简单示例
n := 0
controller := hands.New()
controller.Do(func(ctx context.Context) error {
n++
return nil
})
err := controller.Run()
if err != nil {
// ...
}
fmt.Println(n)
// Output:
// 1
使用Do
方法添加任务,使用Run
方法启动任务。
TaskOption
TaskOption
用于为任务设置一些元数据。
func Priority(priority int32) TaskOption
使用Priority
方法为任务设置优先级。优先级越高,执行顺序越高。
(hands.P()
是hands.Priority()
的别名。)
controller := New()
controller.Do(func(ctx context.Context) error {
fmt.Println("3")
return nil
}, hands.P(1))
controller.Do(func(ctx context.Context) error {
fmt.Println("2")
return nil
}, hands.P(2))
controller.Do(func(ctx context.Context) error {
fmt.Println("1")
return nil
}, hands.P(3))
controller.Run()
// Output:
// 1
// 2
// 3
HandOption
HandOption用于控制任务的执行策略。
func Fastest() HandOption
Fastest()
: 当一个任务完成时,立即返回。
n := 0
controller := hands.New()
controller.Do(func(ctx context.Context) error {
time.Sleep(time.Duration(10) * time.Millisecond)
n += 1
return nil
})
controller.Do(func(ctx context.Context) error {
n += 2
return nil
})
controller.Run(hands.Fastest())
fmt.Println(n)
// Output:
// 2
func Percentage(percentage float32) HandOption
当执行了指定百分比的任务后,返回结果。
n := 0
controller := hands.New()
controller.Do(func(ctx context.Context) error {
n++
return nil
})
controller.Do(func(ctx context.Context) error {
n++
return nil
})
controller.Do(func(ctx context.Context) error {
n++
return nil
})
controller.Do(func(ctx context.Context) error {
n++
return nil
})
controller.Run(hands.Percentage(0.5))
fmt.Println(n)
// Output:
// 2
func Between(l, r int32) HandOption
Between()
: 只执行优先级在指定范围内的任务。
n := 0
controller := hands.New()
controller.Do(func(ctx context.Context) error {
n += 1
return nil
}, hands.P(1))
controller.Do(func(ctx context.Context) error {
n += 2
return nil
}, hands.P(2))
controller.Do(func(ctx context.Context) error {
n += 3
return nil
}, hands.P(3))
controller.Do(func(ctx context.Context) error {
n += 4
return nil
}, hands.P(4))
controller.Run(hands.Between(2, 3))
fmt.Println(n)
// Output:
// 5
注意:如果使用controller.Run()
方法,Between()
范围之外的任务将不会执行,可以使用controller.RunAll()
方法让其他优先级的任务异步执行。
...
controller.RunAll(hands.Between(2, 3))
fmt.Println(n)
time.Sleep(time.Duration(10) * time.Millisecond)
fmt.Println(n)
// Output:
// 5
// 10
func In(in []int32) HandOption
In()
: 只执行指定优先级列表中的任务。
n := 0
controller := hands.New()
controller.Do(func(ctx context.Context) error {
n += 1
return nil
}, hands.P(1))
controller.Do(func(ctx context.Context) error {
n += 2
return nil
}, hands.P(2))
controller.Do(func(ctx context.Context) error {
n += 3
return nil
}, hands.P(3))
controller.Do(func(ctx context.Context) error {
n += 4
return nil
}, hands.P(4))
controller.Run(hands.In([]int32{2, 4}))
fmt.Println(n)
// Output:
// 6
同样,controller.RunAll()
方法也可以在这里使用。
...
controller.RunAll(hands.In([]int32{2, 4}))
fmt.Println(n)
time.Sleep(time.Duration(10) * time.Millisecond)
fmt.Println(n)
// Output:
// 6
// 10
func WithContext(ctx context.Context) HandOption
让任务使用指定的context。
c, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
controller := hands.New()
controller.Do(func(ctx context.Context) error {
time.Sleep(time.Duration(100) * time.Millisecond)
return nil
})
err := controller.Run(hands.WithContext(c))
fmt.Println(err.Error())
// Output:
// context deadline exceeded
所有任务执行完成后的回调
n := 0
controller := hands.New()
controller.Do(func(ctx context.Context) error {
time.Sleep(time.Duration(10) * time.Millisecond)
n++
return nil
})
controller.Do(func(ctx context.Context) error {
time.Sleep(time.Duration(10) * time.Millisecond)
n++
return nil
})
controller.Do(func(ctx context.Context) error {
n += 5
return nil
})
// 这里
controller.Done(func() {
// `True`
assert.Equal(t, n, 7)
})
controller.RunAll(Fastest())
// `True`
assert.Equal(t, n, 5)
time.Sleep(time.Duration(500) * time.Millisecond)
更多关于golang多协程执行控制与返回策略管理插件库hands的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang多协程执行控制与返回策略管理插件库hands的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang多协程执行控制与返回策略管理 - Hands库使用指南
Hands是一个轻量级的Golang协程管理库,它提供了简洁的API来控制并发执行、收集结果以及处理错误。下面我将详细介绍如何使用Hands库来管理多协程任务。
安装Hands
首先安装Hands库:
go get github.com/duke-git/hands
基本使用
1. 简单任务执行
package main
import (
"fmt"
"github.com/duke-git/hands"
"time"
)
func main() {
h := hands.New()
// 添加任务
h.Add(func() (interface{}, error) {
time.Sleep(1 * time.Second)
return "Task1 completed", nil
})
h.Add(func() (interface{}, error) {
time.Sleep(2 * time.Second)
return "Task2 completed", nil
})
// 执行并等待所有任务完成
results, errs := h.Wait()
// 处理结果
fmt.Println("Results:")
for _, res := range results {
fmt.Println(res)
}
// 处理错误
fmt.Println("Errors:")
for _, err := range errs {
fmt.Println(err)
}
}
2. 限制并发数
func main() {
// 限制最多同时运行2个协程
h := hands.New().SetLimit(2)
for i := 0; i < 5; i++ {
id := i
h.Add(func() (interface{}, error) {
time.Sleep(1 * time.Second)
return fmt.Sprintf("Task %d completed", id), nil
})
}
results, _ := h.Wait()
for _, res := range results {
fmt.Println(res)
}
}
高级功能
1. 超时控制
func main() {
h := hands.New().SetTimeout(3 * time.Second)
h.Add(func() (interface{}, error) {
time.Sleep(2 * time.Second)
return "Task1 completed", nil
})
h.Add(func() (interface{}, error) {
time.Sleep(4 * time.Second) // 这个任务会超时
return "Task2 completed", nil
})
_, errs := h.Wait()
for _, err := range errs {
fmt.Println("Error:", err) // 会输出超时错误
}
}
2. 结果处理器
func main() {
h := hands.New()
// 添加结果处理器
h.SetResultHandler(func(result interface{}) {
fmt.Println("Received result:", result)
})
// 添加错误处理器
h.SetErrorHandler(func(err error) {
fmt.Println("Received error:", err)
})
for i := 0; i < 3; i++ {
id := i
h.Add(func() (interface{}, error) {
if id%2 == 0 {
return fmt.Sprintf("Success %d", id), nil
}
return nil, fmt.Errorf("error %d", id)
})
}
h.Wait() // 处理结果和错误会自动被调用
}
3. 任务依赖
func main() {
h := hands.New()
// 第一个任务
task1 := h.Add(func() (interface{}, error) {
return "Task1 result", nil
})
// 第二个任务依赖第一个任务的结果
h.AddWithDeps([]hands.Task{task1}, func(results []interface{}) (interface{}, error) {
task1Result := results[0].(string)
return "Task2 processed: " + task1Result, nil
})
results, _ := h.Wait()
fmt.Println(results[1]) // 输出: Task2 processed: Task1 result
}
最佳实践
- 合理设置并发数:根据任务类型和系统资源设置合适的并发限制
- 及时处理错误:使用错误处理器或检查返回的错误列表
- 利用超时机制:避免因个别任务卡住整个程序
- 任务拆分:将大任务拆分为小任务,充分利用并发优势
- 资源清理:对于需要清理资源的任务,使用defer确保执行
性能考虑
- Hands的轻量级设计使其引入的开销很小
- 对于极高性能要求的场景,可以考虑直接使用sync.WaitGroup和channel
- 对于大量小任务,可以适当增加并发限制数
Hands库通过简洁的API抽象了并发控制的复杂性,使得开发者可以更专注于业务逻辑的实现,同时保证并发执行的安全性和可控性。