不做大哥好多年 不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • Langchain
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核

逍遥子

不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • Langchain
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核
  • Python

  • GO

    • 01.GMP模型 ✅
    • 02.Map原理 ✅
    • 03.sync_map ✅
    • 04.sync.Pool
      • 01.sync.Pool介绍
        • 1、是什么
        • 2、原理
        • 3、怎么用
        • 4、实现细节
        • 5、sync.Pool 的局限性
      • 02.gin中的Context pool
    • 05.垃圾回收 ✅
    • 06.channel
    • 07.内存逃逸
    • 08.内存泄漏
    • 09.mutex锁原理
    • 10.Go常识
    • 50.Golang常犯错误
    • 51.常见坑1~10
  • Java

  • 业务问题

  • 关键技术

  • 项目常识

  • 计算机基础

  • 区块链

  • 常识
  • GO
xiaonaiqiang
2021-06-25
目录

04.sync.Pool

# 01.sync.Pool介绍

# 1、是什么

sync.Pool 适用于那些需要频繁创建和销毁的对象,特别是在短生命周期且对象分配与释放频率很高的场景

  • sync.Pool 是 Go 标准库中的一个并发安全的对象池,用于对象的复用与回收
  • 它可以降低 GC 压力并提高性能,特别是在高频率创建和销毁对象的场景中
  • 当程序请求一个对象时,sync.Pool 首先尝试从池中获取可复用的对象
  • 如果没有可用的对象,则会调用用户提供的函数(如果设置了 New 字段)或返回 nil
  • 当对象不再使用时,程序可以将对象放回池中,供下次复用

# 2、原理

  • sync.Pool 是 sync 包下的一个组件,可以作为保存临时取还对象的一个“池子”
  • Pool 结构体的定义为:
    • Pool 中有两个定义的公共方法,分别是 Put - 向池中添加元素;
    • Get 从池中获取元素,如果没有,则调用 New 生成元素,如果 New 未设置,则返回 nil
type Pool struct {
   noCopy noCopy

   local     unsafe.Pointer // 本地P缓存池指针
   localSize uintptr        // 本地P缓存池大小

   // 当池中没有可能对象时
   // 会调用 New 函数构造构造一个对象
   New func() interface{}
}
1
2
3
4
5
6
7
8
9
10

# 3、怎么用

  • 首先,sync.Pool 是协程安全的,这对于使用者来说是极其方便的
  • 使用前,设置好对象的 New 函数,用于在 Pool 里没有缓存的对象时,创建一个
  • 之后,在程序的任何地方、任何时候仅通过 Get()、Put() 方法就可以取、还对象了
package main

import (
	"fmt"
	"sync"
)

var pool *sync.Pool

type Person struct {
	Name string
}

func initPool() {
	pool = &sync.Pool {
		New: func() interface{} {
			fmt.Println("Creating a new Person")
			return new(Person)
		},
	}
}

func main() {
	initPool()

	p := pool.Get().(*Person)   // get获取不到就会调用方法,创建一个
	p.Name = "first"

	pool.Put(p)  // 使用 Put方法将对象放回 pool池子中

	fmt.Println("Pool 里已有一个对象:&{first},调用 Get: ", pool.Get().(*Person))
	fmt.Println("Pool 没有对象了,调用 Get: ", pool.Get().(*Person))  // 获取后再次获取就没有了,会再次创建
}
/*
Creating a new Person
Pool 里已有一个对象:&{first},调用 Get:  &{first}
Creating a new Person
Pool 没有对象了,调用 Get:  &{}
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 4、实现细节

sync.Pool 在 Go 的 runtime 中有一套复杂的机制来处理对象的存取,主要包括

  • 本地池:
    • 每个 goroutine 维护一个私有池,存储在 sync.Pool 的 local 结构中
    • 私有池中的对象只能被当前 goroutine 访问,这种设计减少了锁的竞争
  • 全局池:
    • 当 goroutine 私有池为空时,sync.Pool 会从全局池中获取对象
    • 全局池中的对象是共享的,需要加锁来确保并发安全
  • GC 影响:
    • Go 运行时会在垃圾回收时清空 sync.Pool,即池中未被使用的对象会在 GC 时被回收
    • 这意味着 sync.Pool 不是一个持久存储的缓存机制,而是一种临时对象复用技术

# 5、sync.Pool 的局限性

  • 非持久缓存:
    • 由于 GC 会清空 sync.Pool 中的对象,因此它不能用于持久缓存
    • 如果需要长时间存储对象,应考虑其他缓存机制(如 map 或 LRU 缓存)
  • 适合短生命周期对象:
    • sync.Pool 主要用于短生命周期的对象复用
    • 如果对象的生命周期较长,使用 sync.Pool 可能并不会带来显著的性能提升
  • 不能精确控制对象数量:
    • sync.Pool 不提供对池中对象数量的控制,因此对象池中的对象数量完全依赖于程序的使用模式和 GC 的行为

# 02.gin中的Context pool

  • 在 web 应用中,后台在处理用户的每条请求时都会为当前请求创建一个上下文环境 Context,用于存储请求信息及相应信息等

  • Context 满足长生命周期的特点,且用户请求也是属于并发环境,所以对于线程安全的 Pool 非常适合用来维护 Context 的临时对象池

  • Gin 在结构体 Engine 中定义了一个 pool:

type Engine struct {
   // ... 省略了其他字段
   pool             sync.Pool
}
1
2
3
4
  • 初始化 engine 时定义了 pool 的 New 函数:
engine.pool.New = func() interface{} {
   return engine.allocateContext()
}

// allocateContext
func (engine *Engine) allocateContext() *Context {
   // 构造新的上下文对象
   return &Context{engine: engine}
}
1
2
3
4
5
6
7
8
9
  • ServeHttp
// 从 pool 中获取,并转化为 *Context
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset()  // reset

engine.handleHTTPRequest(c)

// 再扔回 pool 中
engine.pool.Put(c)
1
2
3
4
5
6
7
8
9
10
上次更新: 2025/2/25 11:09:45
03.sync_map ✅
05.垃圾回收 ✅

← 03.sync_map ✅ 05.垃圾回收 ✅→

最近更新
01
05.快递Agent智能体
06-04
02
200.AI Agent核心概念
06-04
03
105.Agent智能体梳理
06-04
更多文章>
Theme by Vdoing | Copyright © 2019-2025 逍遥子 技术博客 京ICP备2021005373号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式