go语言进阶之字节池与工作池

字节池(byte pool)

在go语言中,字节池是一种用来管理和复用字节切片的内存池。使用字节池可以减少内存分配和垃圾回收的压力,尤其是在频繁使用内存的场景中,如网络编程、文件操作和高并发服务中。

概念学习

什么是字节切片

字节切片(Byte Slice)通常是指用于表示一段连续的字节数组的结构。其核心思想在于提供对自己序列的灵活访问和操作

其中,字节指数据存储的基本单位,切片指从一段数据结构中提取出的一部分内容。

在很多编程语言中,字节切片是用来处理原始二进制数据的一种方式,字节切片通常没有固定长度,可以动态调整。

什么是字节池

字节池是一种内存管理机制,通常用于优化内存的分配和释放,尤其是在高频率的内存操作中,它通过预先分配一块内存池,并跟进需求从池中获取或释放内容,避免了频繁的进行内存分配和释放操作。

字节池的工作原理主要是预先分配一块大内存,当程序需要内存时,从池中取出一定大小的内存,而不是每次都从操作系统中申请,当内存使用完后,返回自己池中等待下一次使用

基本实现

在了解了基本概念后,就可以进入go语言的字节池学习。

go语言中使用的是sync.Pool来创建字节池。

package main

import (
	"fmt"
	"sync"
)

var bytePool = sync.Pool{
	// New 是 sync.Pool 中的一个方法,用来定义获取对象的方式。
	New: func() interface{} {
		// 每次从池中获取不到对象时会调用这个方法来创建新的对象
		return make([]byte, 1024) // 返回一个大小为 1024 字节的切片
	},
}

func main() {
	// 从字节池中获取一个字节切片
	buf := bytePool.Get().([]byte)

	// 使用 buf 做一些操作
	fmt.Printf("buf length: %d\n", len(buf))

	// 使用完字节切片后,放回池中复用
	bytePool.Put(buf)
}

在这段代码中主要有以下3个阶段:

  1. sync.Poll():提供了一个机制来池化对象,以减少内存的分配和垃圾回收,它的New函数定义了当池为空时应该如何创建新对象
  2. bytePoll.Get():从池中获取一个字节切片,如果池中没有对象,New函数会被用来创建一个新的对象
  3. bytePool.Put(buf):将使用过的字节切片放回池中

工作池(Worker Pool)

在go语言中,工作池是一种常见的并发模式,用于管理和调整多个工作任务,通过工作池可以控制并发工作任务的数量,避免过多goroutine同时执行导致系统资源损耗或性能下降。

当然我们也可以将工作池理解为线程池,其主要作用也差不多。

基本实现

package main

import (
	"fmt"
	"sync"
	"time"
)

// 定义任务的类型,任务可以是一个简单的函数
type Task struct {
	ID int
}

// 工作池中的工作函数
func worker(id int, tasks <-chan Task, wg *sync.WaitGroup) {
	defer wg.Done() // 完成后通知 WaitGroup

	for task := range tasks {
		// 模拟任务处理
		fmt.Printf("Worker %d processing task %d\n", id, task.ID)
		time.Sleep(1 * time.Second) // 模拟任务处理的时间
	}
}

// 创建工作池函数
func createWorkerPool(numWorkers int, tasks <-chan Task) *sync.WaitGroup {
	var wg sync.WaitGroup

	// 启动工作 goroutine
	for i := 1; i <= numWorkers; i++ {
		wg.Add(1)
		go worker(i, tasks, &wg)
	}

	return &wg
}

func main() {
	// 创建一个任务队列
	tasks := make(chan Task, 10)

	// 创建工作池,假设池中有 3 个工作 goroutine
	wg := createWorkerPool(3, tasks)

	// 模拟生成任务并添加到任务队列中
	for i := 1; i <= 10; i++ {
		tasks <- Task{ID: i}
	}

	// 关闭任务队列,表示没有更多的任务
	close(tasks)

	// 等待所有工作 goroutine 完成
	wg.Wait()
}

这段代码先定义了一个Task类型,其代表一个类型,每个任务有一个ID

然后工作函数worker是每个工作goroutine执行的内容,每个工作goroutine从任务对了中获取任务并处理,直到队列为空

createWorkerPool函数主要用于接受工作的goroutine的数量numWorkers和任务队列tasks,并启动对应数量的工作goroutine来并发执行任务

然后使用一个有缓存tasks作为任务队列,并将任务放入队列中,goroutine从队列中取出任务进行执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

follycat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值