上一节《Runtime: Golang 之 sync.Pool 源码分析》我们介绍了sync.Pool 的源码分析,本节介绍一个 fasthttp
中引用的一缓存池库 bytebufferpool
,这两个库是同一个开发者。对于这个缓存池库与同类型的几个库的对比,可以参考 https://omgnull.github.io/go-benchmark/buffer/。
建议大家了解一下fasthttp
这个库,性能要比直接使用内置的 net/http
高出很多,其主要原因是大量的用到了缓存池 sync.Pool
进行性能提升。
用法
// https://github.com/valyala/bytebufferpool/blob/18533face0/bytebuffer_example_test.go package bytebufferpool_test import ( "fmt" "github.com/valyala/bytebufferpool" ) func ExampleByteBuffer() { // 从缓存池取 Get() bb := bytebufferpool.Get() // 用法 bb.WriteString("first linen") bb.Write([]byte("second linen")) bb.B = append(bb.B, "third linen"...) fmt.Printf("bytebuffer contents=%q", bb.B) // 使用完毕,放回缓存池 Put() // It is safe to release byte buffer now, since it is no longer used. bytebufferpool.Put(bb) }
全局变量
我们先看一下与其相关的一些常量
const ( // 定位数据索引位置,使用位操作性能比较高效 minBitSize = 6 // 2**6=64 is a CPU cache line size // 数组索引个数 0~19 steps = 20 // 最小缓存对象 和 最大缓存对象大小 minSize = 1 << minBitSize maxSize = 1 << (minBitSize + steps - 1) // 校准阈值, 这里指的调用次数 calibrateCallsThreshold = 42000 // 百分比,校准数据基数 maxPercentile = 0.95 )
对于常量上面已做了注释,如果现在不明白的话没有关系,看完下面就知道它们的作用了。
数据类型
主要有两个相关的数据结构,分别为 Pool
和 ByteBuffer
,其实现也比较的简单。
数据结构
// ByteBuffer provides byte buffer, which can be used for minimizing // memory allocations. // // ByteBuffer may be used with functions appending data to the given []byte // slice. See example code for details. // // Use Get for obtaining an empty byte buffer. type ByteBuffer struct { // B is a byte buffer to use in append-like workloads. // See example code for details. B []byte } // Pool represents byte buffer pool. // // Distinct pools may be used for distinct types of byte buffers. // Properly determined byte buffer types with their own pools may help reducing // memory waste. type Pool struct { calls [steps]uint64 calibrating uint64 defaultSize uint64 maxSize uint64 pool sync.Pool } var defaultPool Pool
字段解释
calls
缓存对象大小调用次数统计,steps
就是我们上面定义的常量。主要用来统计每类缓存大小的调用次数。steps 具体的值会使用一个index()
函数通过位操作的方式计算出来它在这个数组的索引位置;calibrating
校标标记。0 表示未校准,1表示正在校准。校准需要一个过程,校准完成后需要从1恢复为 0;defaultSize
缓存对象默认大小。我们知道当从 pool 中获取缓存对象时,如果池中没有对象可取,会通过调用 一个New()
函数创建一个新对象返回,这时新创建的对象大小为defaultSize
。当然这里没有使用New()
函数,而是直接创建了一个 指定默认大小的ByteBuffer
;maxSize
允许放入pool
池中的最大对象大小,只有<maxSize
的对象才允许放放池中
这里的变量 defaultPool 是一个全局的 Pool 对象。
Continue reading