Golang 的 sync.Pool设计思路与原理

基于Go 1.12

使用实例

sync.Pool设计的目的是用来保存和复用临时对象,以减少内存分配,降低CG压力。

Pool对外暴露的主要有三个接口:

func (p *Pool) Get() interface{
   }

func (p *Pool) Put(x interface{
   })

New func() interface{
   }

Get 返回 Pool 中的任意一个对象。如果 Pool 为空,则调用 New 返回一个新创建的对象。

下面是一个实例代码:

package main

import (
	"log"
	"sync"
)

func main()  {
   
	// 建立对象
	var pipe = &sync.Pool{
   New:func()interface{
   }{
   return "Hello, BeiJing"}}
	
	// 准备放入的字符串
	val := "Hello,World!"
	
	// 放入
	pipe.Put(val)
	
	// 取出
	first := pipe.Get().(string)
	
	// 再取就没有了,会自动调用NEW
	second := pipe.Get().(string)
}

底层数据结构

sync.Pool 是一个临时对象池。一句话来概括,sync.Pool 管理了一组临时对象,当需要时从池中获取,使用完毕后从再放回池中,以供他人使用。

数据结构定义如下:

type Pool struct {
   
	noCopy noCopy

	local     unsafe.Pointer // local,固定大小per-P池, 实际类型为 [P]poolLocal
	localSize uintptr        // local array 的大小
	//  New 方法在 Get 失败的情况下,选择性的创建一个值, 否则返回nil
	New func() interface{
   }
}

type poolLocal struct {
   
	poolLocalInternal

	// 将 poolLocal 补齐至两个缓存行的倍数,防止 false sharing,
	// 每个缓存行具有 64 bytes,即 512 bit
	// 目前我们的处理器一般拥有 32 * 1024 / 64 = 512 条缓存行
	pad [128 - unsafe.Sizeof(poolLocalInternal{
   })%128]byte
}

// Local per-P Pool appendix.
type poolLocalInternal struct {
   
	private interface{
   }   // 只能被局部调度器P使用
	shared  []interface{
   } // 所有P共享
	Mutex                 // 访问共享数据域的锁
}

一个poolLocal与一个P绑定,也就是说一个P持有一个poolLocal。每个 poolLocal 的大小均为缓存行的偶数倍,包含一个 private 私有对象、shared 共享对象 slice 以及一个 Mutex 并发锁。

Put

Put的过程就是将临时对象放进 Pool 里面。源码如下:

func (p *Pool) Put(x interface{
   }) {
   
	if x == <
  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值