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


猜你喜欢
- 图片无缝滚动就是图片一直不停的滚动,好像没有无穷无尽似的,实际上就是几张图片不停的循环,但是看不出有从最后面切换到最前面的效果,这就是无缝滚
- 1. pathlib库介绍相比常用的 os.path 而言,pathlib 对于目录路径的操作更简洁也更贴近 Pythonic(Python
- 索引和切片是NumPy中最重要最常用的操作。熟练使用NumPy切片操作是数据处理和机器学习的前提,所以一定要掌握好。文档:https://d
- 本文整理了3种鼠标经过图片,图片边框加粗或改变颜色的方法,希望大家喜欢。下面3中只是提供了一个方法,具体的鼠标经过图片的样式,你自己可以修改
- 通过win32 COM接口实现软件的操作本质上来看跟直接操作软件一致,这跟我之前经常用的通过各种扩展的组件或者库实现各种文件的处理有较大的差
- 前言Typora是一款非常使用的笔记工具,对于程序员非常友好,在2021年11月23日,Typora 正式发布 1.0 版本,进入了付费时代
- 在此之前,我一直都在研究JavaScript相关的反调试技巧。但是当我在网上搜索相关资料时,我发现网上并没有多少关于这方面的文章,而且就算有
- 今天遇到了这样一个问题,使用matplotlib绘制热图数组中横纵坐标自然是图片的像素排列顺序,但是这样带来的问题就是画出来的x,y轴中坐标
- 特殊情况有 * ^ : | . \一、单个符号作为分隔符String address="上海\上海市|闵行区\吴中路";
- 环境系统:Centos7.2 服务:Nginx1:下载PHP7.0.2的安装包解压,编译,安装: $ cd /usr/s
- 出现这个问题解决方法:点击File > Settings > Tools > Server Certificates &g
- MySQL内部复制功能是建立在两个或两个以上服务器之间,通过设定它们之间的主-从关系来实现的。其中一个作为主服务器,其它的作为从服务器。本节
- QMainWindow基本介绍QMainWindow主窗口为用户提供了一个应用程序框架,它有自己的布局,可以在布局中添加控件。窗口类型介绍P
- number(<p>,<s>)精度p取值范围1~38有效位s取值范围-84~127最高整数位数=p-ss正数,小数点
- 一、窗口函数的基本用法从MySQL8之后才开始支持窗口函数<窗口函数> OVER ([PARTITION BY <用于分组
- WINDOWS 下装MongoDB先去官网下载 :https://www.mongodb.com/download-center
- 在opencv中,特征检测、描述、匹配都有集成的函数。vector<DMatch> bestMatches;用来存储得到的匹配点
- 最近,在项目开发过程中,碰到了数据库死锁问题,在解决问题的过程中,笔者对MySQL InnoDB引擎锁机制的理解逐步加深。案例如下:在使用S
- 前言:c3p0 是一个开源的数据库连接池,实现了 JDBC 3 规范;本文主要介绍 c3p0 的基本使用,文中使用到的软件版本:Java 1
- Python 是一门优雅的语言,简洁的语法,强大的功能。当然丰富的第三方库,更能加速开发。那么问题来了,如何安装这些第三方库(包)呢?安装第