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

1 回复

更多关于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
}

最佳实践

  1. 合理设置并发数:根据任务类型和系统资源设置合适的并发限制
  2. 及时处理错误:使用错误处理器或检查返回的错误列表
  3. 利用超时机制:避免因个别任务卡住整个程序
  4. 任务拆分:将大任务拆分为小任务,充分利用并发优势
  5. 资源清理:对于需要清理资源的任务,使用defer确保执行

性能考虑

  • Hands的轻量级设计使其引入的开销很小
  • 对于极高性能要求的场景,可以考虑直接使用sync.WaitGroup和channel
  • 对于大量小任务,可以适当增加并发限制数

Hands库通过简洁的API抽象了并发控制的复杂性,使得开发者可以更专注于业务逻辑的实现,同时保证并发执行的安全性和可控性。

回到顶部