Go编程库Sync.Pool用法示例详解

作者:小马别过河 时间:2024-02-01 04:48:21 

场景

go 如果频繁地创建、销毁对象(比如 http 服务的 json 对象,日志内容等),会对 GC 造成压力。比如下面的 Log 函数,在高并 * 况下,需要频繁地创建和销毁 buffer。

func Log(w io.Writer, key, val string) {
b := new(bytes.Buffer)
 // 按一定的格式打印日志,这一段不是重点
b.WriteString(time.Now().UTC().Format(time.RFC3339))
b.WriteByte(' ')
b.WriteString(key)
b.WriteByte('=')
b.WriteString(val)
b.WriteByte('\n')
w.Write(b.Bytes())
}

这时候可以考虑复用这些 buffer。我们可以维护一个 buffer 的对象池,需要的时候从对象池拿 buffer,用完放回对象池。这时候就推荐使用 sync.Pool 了。

sync.Pool 维护着一组对象池,需要时从对象池拿对象,不需要放回对象池就可以了。它有这些特点:

  • 忙时会自动扩容对象池,闲时会自动缩容;

  • 线程安全;

  • 对象池的对象,会未经通知地自动删除;

  • 不能被 copy。

用法

创建

初始化时指定 New 方法。sync.Pool 会通过 New 方法创建对象池的对象。一般返回一个指针。

// 从对象池里取 buffer 时,如果池里没 buffer了,则调用 New 创建一个新的。
var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}

GET & PUT

通过 Get 获取对象池的对象。当使用完毕,通过 Put 把对象返回对象池。

b := bufPool.Get().(*bytes.Buffer)  // 从对象池拿 buffer 对象
 // 操作对象,这个不重要
b.Reset()
b.WriteString(time.Now().UTC().Format(time.RFC3339))
 // 操作完放回对象池
bufPool.Put(b)

优化 Log 函数

Log 函数可以使用 sync.Pool 的优化,代码如下:

var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func LogWithPool(w io.Writer, key, val string) {
 // 从对象池拿 buffer
b := bufPool.Get().(*bytes.Buffer)
b.Reset()
 // 按一定的格式打印日志,这一段不是重点
b.WriteString(time.Now().UTC().Format(time.RFC3339))
b.WriteByte(' ')
b.WriteString(key)
b.WriteByte('=')
b.WriteString(val)
b.WriteByte('\n')
w.Write(b.Bytes())
 // 放回对象池
bufPool.Put(b)
}

性能测试

我们对两个函数进行性能测试

// 不使用 sync.Pool
func BenchmarkLog(b *testing.B) {
writer := os.NewFile(0, os.DevNull)
for n := 0; n < b.N; n++ {
Log(writer, "path", "/search?a=flowers")
}
}
// 使用 sync.Pool 复用
func BenchmarkLogWithPool(b *testing.B) {
writer := os.NewFile(0, os.DevNull)
for n := 0; n < b.N; n++ {
LogWithPool(writer, "path", "/search?a=flowers")
}
}

结果:

> go test -bench . -benchmem
goos: darwin
goarch: amd64
pkg: example/pool
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkLog-8                   1849365               635.0 ns/op           112 B/op          2 allocs/op
BenchmarkLogWithPool-8           1993304               614.4 ns/op            48 B/op          1 allocs/op
PASS
ok      example/pool    4.333s

相比之下,使用 Sync.Pool 和不使用的时候,内存的使用比为 48:112,优化效果还是挺明显的。

参考:

[1]. pkg.go.dev/sync#Pool

来源:https://juejin.cn/post/7166051649335590925

标签:Go,库,Sync.Pool
0
投稿

猜你喜欢

  • SQL Server时间戳功能与用法详解

    2024-01-27 23:14:20
  • Python字符串内置函数功能与用法总结

    2022-08-17 00:29:29
  • yii框架中的Url生产问题小结

    2023-07-20 14:08:45
  • 由黄钻等级图标处理引发的思考

    2009-11-16 12:37:00
  • python中的subprocess.Popen()使用详解

    2023-08-01 18:55:23
  • 影响SQL Server性能的三个关键点

    2009-03-09 13:11:00
  • JavaScript实现点击按钮切换网页背景色的方法

    2024-04-16 09:02:43
  • vue日期时间工具类详解

    2024-06-07 16:06:22
  • 利用pyinstaller或virtualenv将python程序打包详解

    2022-08-01 10:37:52
  • python tkinter模块的简单使用

    2021-11-20 16:52:33
  • python自动生成证件号的方法示例

    2023-05-25 07:42:11
  • python 追踪except信息方式

    2022-10-07 13:46:02
  • JS组件Bootstrap Select2使用方法解析

    2024-04-16 09:49:36
  • Sql Server之数据类型详解

    2024-01-20 08:08:11
  • HeidiSQL工具导出导入MySQL数据

    2024-01-19 23:00:32
  • 简单聊聊Golang中defer预计算参数

    2023-07-22 03:55:09
  • 详解python中递归函数

    2022-04-17 19:40:55
  • js控制div弹出层实现方法

    2023-10-15 05:53:28
  • python通过安装itchat包实现微信自动回复收到的春节祝福

    2022-07-09 20:36:26
  • Python中 Lambda表达式全面解析

    2021-07-05 04:58:01
  • asp之家 网络编程 m.aspxhome.com