sync.Pool 的作用

先看看官方文档怎样说的吧,我截取了官方文档的第一句。

// A Pool is a set of temporary objects that may be individually saved and retrieved.
.....
  • 简单翻译一下的意思是:池是一组可以单独保存和检索的临时对象。既然可以单独保存和检索的临时对象,对于大量重复地创建许多对象,造成 GC 的工作量巨大。而mygin的模式是 责任链模式 ,因此满足使用 sync.Pool。
  • 一个 Pool 可以安全地由多个 goroutine 同时使用。池的目的是缓存已分配但未使用的项目以供以后重用,从而减轻垃圾回收器的压力。
  • sync.Pool 是可伸缩的,同时也是并发安全的,其大小仅受限于内存的大小。sync.Pool 用于存储那些被分配了但是没有被使用,而未来可能会使用的值。这样就可以不用再次经过内存分配,可直接复用已有对象,减轻 GC 的压力,从而提升系统的性能。

    以上都是源于官方文档翻译的,文档中还提到fmt包中,打印也使用了sync.Pool,感兴趣的可以点进源码查看。

sync.Pool 使用

sync.Pool 的使用方式非常简单:

只需要实现New函数即可。对象池中没有对象时,将会调用New函数创建,我使用了mygin中的context

创建

var contextPool = sync.Pool{
New: func() interface{} {
return new(Context)
},
}

使用和归还

c := contextPool.Get().(*Context)
json.Marshal(c)
contextPool.Put(c)

测试

func BenchmarkUnmarshal(b *testing.B) {
for n := 0; n < b.N; n++ {
c := &Context{} json.Marshal(c)
}
} func BenchmarkUnmarshalWithPool(b *testing.B) {
for n := 0; n < b.N; n++ {
c := contextPool.Get().(*Context)
json.Marshal(c)
contextPool.Put(c)
}
}

测试结果:

go test -bench . -benchmem
goos: linux
goarch: amd64
pkg: github.com/scott-pb/mygin
cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
BenchmarkUnmarshal-8 5888780 208.1 ns/op 144 B/op 2 allocs/op
BenchmarkUnmarshalWithPool-8 7261801 165.0 ns/op 48 B/op 1 allocs/op
PASS
ok github.com/scott-pb/mygin 2.808s

在这个例子中,可以看出,使用了 sync.Pool 后,内存占用仅为未使用的 48/144= 1/3,对 GC 的影响就很大了。执行速度也快了,当然不同的设备测试结果也会不同。

测试源码

我把测试源码放在了mygin中 mygin/context_test.go

mygin使用sync.Pool

修改mygin/engine.go

修改engine.go中实例化conetxt的部分具体在ServeHTTP 方法中

修改前

//实例化一个下上文
c := &Context{
Request: r,
Writer: w,
Params: params,
handlers: handlers,
index: -1,
}

修改后

//从pool中取
c := e.pool.Get().(*Context)
c.Request = r
c.Writer = w
c.Params = params
c.handlers = handlers
c.index = -1 // 执行处理函数链
c.Next() //归还到pool中
e.pool.Put(c)

mygin测试

main方法代码如下

package main

import (
"fmt"
"github.com/scott-pb/mygin"
"net/http"
) func main() { r := mygin.Default()
group := r.Group("/api")
group.GET("/test", func(c *mygin.Context) {
c.String(http.StatusOK, "success!\n")
}) err := r.Run(":8088")
if err != nil {
fmt.Println(err)
}
}

curl测试

curl -i http://localhost:8088/api/test
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Thu, 01 Feb 2024 05:08:52 GMT
Content-Length: 9 success!

这样mygin的context上下文就加入了Pool池,对于高并发情况下的GC压力会减轻不少。我设计的上下文中内容很少,随着功能的增多,效果会更加明显。

Mygin上下文之sync.Pool复用的更多相关文章

  1. [Go] sync.Pool 的实现原理 和 适用场景

    摘录一: Go 1.3 的 sync 包中加入一个新特性:Pool. 官方文档可以看这里 http://golang.org/pkg/sync/#Pool 这个类设计的目的是用来保存和复用临时对象,以 ...

  2. Golang 临时对象池 sync.Pool

    Go 1.3 的sync包中加入一个新特性:Pool.官方文档可以看这里http://golang.org/pkg/sync/#Pool 这个类设计的目的是用来保存和复用临时对象,以减少内存分配,降低 ...

  3. 深度解密 Go 语言之 sync.Pool

    最近在工作中碰到了 GC 的问题:项目中大量重复地创建许多对象,造成 GC 的工作量巨大,CPU 频繁掉底.准备使用 sync.Pool 来缓存对象,减轻 GC 的消耗.为了用起来更顺畅,我特地研究了 ...

  4. 多图详解Go的sync.Pool源码

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的go的源码时14.4 Pool介绍 总所周知Go 是一个自动垃圾回收的编程语言 ...

  5. sync.Pool:提高Go语言程序性能的关键一步

    1. 简介 本文将介绍 Go 语言中的 sync.Pool并发原语,包括sync.Pool的基本使用方法.使用注意事项等的内容.能够更好得使用sync.Pool来减少对象的重复创建,最大限度实现对象的 ...

  6. sync.Pool的使用

    一定要搞明白sync.Pool的正确用法,避免出现以下问题: kline := this.pool.Get() defer this.pool.Put(kline) kline.UnMarshal(d ...

  7. 深入Golang之sync.Pool详解

    我们通常用golang来构建高并发场景下的应用,但是由于golang内建的GC机制会影响应用的性能,为了减少GC,golang提供了对象重用的机制,也就是sync.Pool对象池. sync.Pool ...

  8. go语言学习--go的临时对象池--sync.Pool

    一个sync.Pool对象就是一组临时对象的集合.Pool是协程安全的. Pool用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力.一个比较好的例子是fmt包,fmt包总 ...

  9. golang sync.Pool包的使用和一些注意地方

    package main; import ( "sync" "fmt" "net" "runtime" ) //sync ...

  10. sync.Pool 资源池

    sync.Pool type Pool struct { // 可选参数New指定一个函数在Get方法可能返回nil时来生成一个值 // 该参数不能在调用Get方法时被修改 New func() in ...

随机推荐

  1. UVA 156 Ananagrams STL应用

    https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&prob ...

  2. Educational Codeforces Round 110 (Rated for Div. 2) (AB签到,C题双指针,D题DP好题)

    补题链接:Here 1535A. Fair Playoff 四名选手参加了季后赛.比赛按以下方案进行:第一名选手与第二名选手比赛,第三名选手与第四名选手比赛,然后两人中的获胜者进入决赛. 众所周知,在 ...

  3. Redis 内存优化在 vivo 的探索与实践

    作者:vivo 互联网服务器团队- Tang Wenjian 一. 背景 使用过 Redis 的同学应该都知道,它基于键值对(key-value)的内存数据库,所有数据存放在内存中,内存在 Redis ...

  4. vivo 大规模特征存储实践

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/u1LrIBtY6wNVE9lzvKXWjA作者:黄伟锋 本文旨在介绍 vivo 内部的特征存储 ...

  5. 【调试】crash使用方法

    crash简介 crash是redhat的工程师开发的,主要用来离线分析linux内核转存文件,它整合了gdb工具,功能非常强大.可以查看堆栈,dmesg日志,内核数据结构,反汇编等等. crash支 ...

  6. Kafka 社区KIP-405中文译文(分层存储)

    原文链接:https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage 译者:Kafka KIP- ...

  7. C#设计模式01——单例模式的三种写法

    第一种 //在方法里new ,这里使用 双if-lock public class SingleFirst { private static SingleFirst _SingleFirst; pri ...

  8. python进度条实现的几种方法

    一.普通进度条(time实现) import time def progress_bar(): for i in range(101): print(f'\rProgress: {"#&qu ...

  9. [转帖]Oracle如何重启mmon/mmnl进程(AWR自动采集)

    https://www.cnblogs.com/jyzhao/p/10119854.html 学习一下 环境:Oracle 11.2.0.4 RAC现象:sysaux空间满导致无法正常生成快照,清理空 ...

  10. [转帖]Windows平台下使用 Rclone 挂载 OneDrive 为本地硬盘

    https://zhuanlan.zhihu.com/p/139200172 Rclone (rsync for cloud storage) 是一个命令行程序,用于同步文件和目录,支持常见的 Ama ...