Go语言学习
  • README
  • Go 基础
    • go语言介绍
    • go语言主要特性
    • go内置类型和函数
    • init函数和main函数
    • 下划线
    • iota
    • 字符串
    • 数据类型:数组与切片
    • 数据类型:byte、rune与字符串
    • 变量的5种创建方式
    • 数据类型:字典
    • 指针
    • 数据类型:指针
    • 类型断言
    • 流程控制:defer延迟执行
    • 异常机制:panic和recover
    • 函数
    • go依赖管理
    • go中值传递、引用传递、指针传递区别
  • 标准库
    • Go net/http包
  • 数据结构
    • 哈希表
      • 为什么对 map 的 key 或 value 进行取址操作是不允许的
  • Gin
    • gin 快速开始
    • gin-swagger用法
  • Go 进阶
    • Go 指针
    • Go 中的 GC 演变是怎样的?
    • Go 的堆和栈
  • 面向对象
    • make 和 new 的区别
    • new(T) 和 &T{} 有什么区别?
  • 并发编程
    • Channel
    • Go语言 CSP 并发模型
    • GMP 模型原理
      • GMP 模型为什么要有 P ?
    • Go 协程池(goroutine pool)
    • Go语言常见的并发模式
    • Go并发实践:主动停止goroutine
  • 最佳实践
    • 发布Go语言模块
  • 软件包
    • 常用的GoLang包工具
    • Go的UUID生成
    • 现代化的命令行框架Cobra
    • 配置解析神器Viper
    • Go发送邮件gomail
    • Go反射框架Fx
    • NSQ消息队列的使用
    • Go爬虫框架colly
    • grpc-go 的安装和使用
Powered by GitBook
On this page

Was this helpful?

  1. 并发编程

Go 协程池(goroutine pool)

在Go语言中,协程池(goroutine pool)是一种用于管理和重用协程(goroutine)的机制。协程是Go语言中轻量级的并发执行单位,可以看作是比线程更轻量级的并发处理方式。

使用协程池的好处是减少创建和销毁协程的开销,通过重用已有的协程来执行任务,提高程序的性能和效率。

以下是一个简单的实现协程池的示例:

package main

import (
	"fmt"
	"sync"
)

// 任务结构体
type Task struct {
	ID int // 任务ID
}

// 协程池结构体
type Pool struct {
	WorkerNum   int           // 协程池中的协程数量
	TaskQueue   chan *Task    // 任务队列
	WG          sync.WaitGroup // 用于等待所有协程完成任务
	StopChannel chan struct{} // 停止信号通道
}

// 创建新的协程池
func NewPool(workerNum, queueSize int) *Pool {
	return &Pool{
		WorkerNum:   workerNum,
		TaskQueue:   make(chan *Task, queueSize),
		StopChannel: make(chan struct{}),
	}
}

// 开始执行任务
func (p *Pool) Start() {
	// 创建指定数量的协程
	for i := 0; i < p.WorkerNum; i++ {
		go p.worker()
	}
}

// 添加任务到任务队列
func (p *Pool) AddTask(task *Task) {
	p.TaskQueue <- task
}

// 关闭协程池
func (p *Pool) Shutdown() {
	close(p.StopChannel)
	p.WG.Wait()
}

// 协程执行的具体任务
func (p *Pool) worker() {
	// 增加等待组计数
	p.WG.Add(1)

	// 循环监听任务队列和停止信号通道
	for {
		select {
		case task := <-p.TaskQueue:
			// 执行任务
			fmt.Printf("Worker %d is processing task %d\n", p.WorkerNum, task.ID)
		case <-p.StopChannel:
			// 收到停止信号,结束协程
			p.WG.Done()
			return
		}
	}
}

func main() {
	pool := NewPool(3, 10)
	pool.Start()

	// 添加一些任务到协程池
	for i := 0; i < 5; i++ {
		task := &Task{ID: i}
		pool.AddTask(task)
	}

	// 关闭协程池
	pool.Shutdown()
}

在上述示例中,我们首先定义了一个Task结构体表示要执行的任务。然后创建了一个Pool结构体作为协程池,其中包含了协程数量、任务队列、等待组和停止信号通道等字段。

通过NewPool函数创建一个新的协程池,然后调用Start方法启动协程池中的协程。接下来,使用AddTask方法添加任务到任务队列中。

协程的具体执行逻辑定义在worker方法中,通过无限循环监听任务队列和停止信号通道。当有任务到达时,协程从任务队列中取出任务并执行;当收到停止信号时,协程结束执行并减少等待组计数。

最后,在main函数中创建一个协程池实例,添加一些任务,并调用Shutdown方法关闭协程池。

需要注意的是,上述示例只是一个简单的协程池实现,仅用于演示基本原理。在实际应用中,可能还需要考虑更多细节,例如协程的生命周期管理、错误处理、任务超时等。

Go语言的生态系统中有一些非常流行和好用的第三方协程池库。以下是其中几个比较受欢迎的库:

  1. ants:https://github.com/panjf2000/ants ants 是一个高性能且可扩展的协程池库。它具有灵活的配置选项,可以控制协程池的大小、限制并发数等。ants 还提供了丰富的功能,例如任务超时处理和异步结果获取。

  2. workerpool:https://github.com/gammazero/workerpool workerpool 是一个简单而高效的协程池库,专注于执行固定数量的工作协程。它提供了清晰的 API,使用起来很方便,并且支持任务队列和错误处理。

  3. tunny:https://github.com/Jeffail/tunny tunny 是一个轻量级的协程池库,设计初衷是为了简化并行任务的管理。它提供了简单的接口以及对任务优先级的支持。

这些库都得到了广泛的应用和积极的社区维护,可以根据自己的需求选择合适的库来构建协程池。在选择库之前,建议查看其文档和示例代码,以了解其特性和用法,并与项目需求进行匹配。

PreviousGMP 模型为什么要有 P ?NextGo语言常见的并发模式

Last updated 1 year ago

Was this helpful?