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
猜你喜欢
- 简介python 动态执行字符串代码片段(也可以是文件), 一般会用到exec,eval。execexec_stmt ::= "e
- 需求:1.用户输入密码正确登录2.用户输入密码错误退出并调用函数继续输入3.用户输入密码符合原先给定的一个值时,允许用户重置密码,并且可以用
- 我们在建立一个大型网站的时候,往往会包括很多相同的页面框架模式,甚至一些细节元素都是相同的。但令人困扰
- 循环结构的应用场景如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就
- 严正声明:本文仅限于技术讨论,严禁用于其他用途。基础知识socket通信模块:针对TCP/IP协议簇进行的程序封装,在Windows/Lin
- CSS是众所周知且应用广泛的网站样式语言,在它的版本三(CSS3)计划中,新增了一些能够节省时间的特性。尽管只有当前最新了浏览器
- 通过LogMiner实现Oracle数据同步迁移为了实现Oracle数据库之间的数据同步,网上的资料比较少的时候。最好用的Oracle数据库
- 本文实例讲述了php的RSA加密解密算法原理与用法。分享给大家供大家参考,具体如下:最近因为工作的需要,要倒腾支付宝支付相关的知识,因为支付
- 1、要连接MySql数据库必须首先下载MySql官方的连接.net的文件,文件下载地址为http://dev.mysql.com/downl
- 直接上代码:#!/usr/bin/python # Filename s5.py # Python Dynamic Socks5 Proxy
- import socketdef open_tcp_socket(remotehost,servicename): &
- 在大三的时候,一直就想搭建属于自己的一个博客,但由于各种原因,最终都不了了之,恰好最近比较有空,于是就自己参照网上的教程,搭建了属于自己的博
- 前言无论是自己要在精心P过的自拍上添加个性文字,或者是摄影爱好者要在拍摄的作品里添加水印,亦或是在网页或者移动应用中实时生成文字和图片的组合
- 下载8000首儿歌的python的代码:#-*- coding: UTF-8 -*-from pyquery import PyQuery
- 特点python的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量能被访问的范围。即Python变量的作用域由变量所在源代码中的位置
- python批量命名照片的具体代码,供大家参考,具体内容如下废话不多说,上效果图全部代码from tkinter import *impor
- 问题你想使用一个Python字典存储数据,并将它转换成XML格式。解决方案尽管 xml.etree.ElementTree 库通常用来做解析
- 右击开始图标,打开“命令提示符(管理员)”。1、输入代码,停止服务。 net stop M
- 目录安装简单使用复杂用法搞定麻烦需求总结工欲善其事,必先利其器!我们想要更轻松更有效率地开发,必须学会一些“高级”技能。前不久看到一位 Py
- Python 中的 Operator 模块可以让它支持函数式编程。1 计算函数假设我们需要一个计算阶乘的函数,一般做法是使用递归。如果使用函