• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

    golang sync.Pool 指针数据覆盖问题解决

    发布者: 琛瑞6678 | 发布时间: 2025-8-14 09:52| 查看数: 14| 评论数: 0|帖子模式

    场景


    1. sync.Pool设置
    1. var stringPool = sync.Pool{
    2.         New: func() any {
    3.                 return new([]string)
    4.         },
    5. }

    6. func NewString() *[]string {
    7.         v := stringPool.Get().(*[]string)
    8.         return v
    9. }

    10. func PutString(s *[]string) {
    11.         if s == nil {
    12.                 return
    13.         }

    14.         if cap(*s) > 2048 {
    15.                 s = nil
    16.         } else {
    17.                 *s = (*s)[:0]
    18.                 stringPool.Put(s)
    19.         }
    20. }
    复制代码
    2.使用sync.Pool
    1. func Test_Pool(t *testing.T) {
    2.         dataSlice1 := demoData()
    3.         dataSlice2 := demoData()
    4.         dataSlice2[1] = "test4"

    5.         fmt.Printf("dataSlice1:%v %p,dataSlice2:%v %p\n", dataSlice1, dataSlice1, dataSlice2, dataSlice2)
    6. }

    7. func demoData() []string {
    8.         strsPtr := NewString()
    9.         strs := *strsPtr
    10.         defer func() {
    11.                 *strsPtr = strs
    12.                 PutString(strsPtr)
    13.         }()

    14.         strs = append(strs, "test1", "test2")
    15.         return strs
    16. }
    复制代码
    打印结果:dataSlice1:[test1 test4] 0xc0000a6400,dataSlice2:[test1 test4] 0xc0000a6400
    可以看到两个slice地址相同,内部使用同一个地址的数组,导致两次获取的数据互相影响

    3.解决方法1
    1. func Test_Pool(t *testing.T) {
    2.         dataSlice1 := demoData()
    3.         dataSlice2 := demoData()
    4.         dataSlice2[1] = "test4"

    5.         fmt.Printf("dataSlice1:%v %p,dataSlice2:%v %p\n", dataSlice1, dataSlice1, dataSlice2, dataSlice2)
    6. }

    7. func demoData() []string {
    8.         strsPtr := NewString()
    9.         strs := *strsPtr
    10.         defer func() {
    11.                 *strsPtr = strs
    12.                 PutString(strsPtr)
    13.         }()

    14.         strs = append(strs, "test1", "test2")

    15.         // 深复制
    16.         var items = make([]string, len(strs))
    17.         copy(items, strs)

    18.         return items
    19. }
    复制代码
    使用深复制,在put回sync.Pool中之前把数据复制返回,但这样资源池失去了意义,获取到资源后有进行了一次内存的申请

    4.解决方法2

    我们看下golang语言源码怎么解决的
    参考 go/src/fmt/print.go 302行 Fprintln方法
    1. func Fprintln(w io.Writer, a ...any) (n int, err error) {
    2.         p := newPrinter()
    3.         p.doPrintln(a)
    4.         n, err = w.Write(p.buf)
    5.         p.free()
    6.         return
    7. }
    复制代码
    可以看到306行有p.free()代码,newPrinter()和free()之间进行数据处理,数据处理完成之后再把资源返回给sync.Pool

    总结

    不是任何场景都适合用sync.Pool,需要关注并发情况下资源池中数据同步修改影响的问题。
    到此这篇关于golang sync.Pool 指针数据覆盖问题解决的文章就介绍到这了,更多相关golang sync.Pool 指针覆盖内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    来源:互联网
    免责声明:如果侵犯了您的权益,请联系站长(1277306191@qq.com),我们会及时删除侵权内容,谢谢合作!

    最新评论

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表