sync.Pool 在 Go 语言中是一个非常有用的同步缓存池,主要用于存储和复用临时对象,以减少内存分配的开销。它特别适合于那些生命周期短、创建成本较高的对象,如解析JSON时的临时缓冲区、数据库连接池中的连接对象等。
sync.Pool 的基本用法
sync.Pool 提供了 Get 和 Put 方法来从池中获取和放回对象。当从池中获取对象时,如果池为空,Get 方法会返回 nil 或者一个由 New 字段指定的函数生成的新对象(如果设置了 New 字段的话)。
示例代码
下面是一个使用 sync.Pool 来缓存和复用字符串缓冲区的简单示例:
package main
import (
	"bytes"
	"fmt"
	"sync"
)
// 创建一个 sync.Pool 实例,用于存储 *bytes.Buffer
var bufferPool = sync.Pool{
	New: func() interface{} {
		// 如果没有可用的缓冲区,则创建一个新的 *bytes.Buffer
		return &bytes.Buffer{}
	},
}
func main() {
	// 从池中获取一个 *bytes.Buffer
	buf := bufferPool.Get().(*bytes.Buffer)
	buf.WriteString("Hello, sync.Pool!")
	fmt.Println(buf.String()) // 输出: Hello, sync.Pool!
	// 使用完毕后,将缓冲区放回池中
	buf.Reset() // 重置缓冲区,避免内存泄漏
	bufferPool.Put(buf)
	// 再次从池中获取时,将可能获取到之前放回的那个缓冲区(如果它还没有被GC回收)
	anotherBuf := bufferPool.Get().(*bytes.Buffer)
	anotherBuf.WriteString("Another use of sync.Pool")
	fmt.Println(anotherBuf.String()) // 输出: Another use of sync.Pool
	// 使用完毕后,同样需要放回池中
	anotherBuf.Reset()
	bufferPool.Put(anotherBuf)
}
注意事项
- sync.Pool中的对象可能会在垃圾回收时被清理掉,因此不能依赖- sync.Pool来持久化存储重要数据。
- sync.Pool并不保证对象的唯一性或线程安全性,它仅仅是一个缓存池,使用时需要根据具体需求进行同步控制。
- 当 Get方法调用时,如果池中没有可用的对象,且New字段被设置,sync.Pool会调用New函数来生成一个新的对象。但是,请注意,New函数的调用是在没有可用对象时才进行,这意味着在高并发场景下,可能会有多个New调用同时发生,生成多个新的对象。因此,New函数的实现应该尽量简单且高效。