目录
- 场景
- 1. sync.Pool设置
- 2.使用sync.Pool
- 3.解决方法1
- 4.解决方法2
- 总结
场景
1. sync.Pool设置
var stringPool = sync.Pool{ New: func() any { return new([]string) }, } func NewString() *[]string { v := stringPool.Get().(*[]string) javascript return v } func PutString(s *[]string) { if s == nil { retuhttp://www.devze.comrn } if cap(*s) > 2048 { s = nil } else { *s = (*s)[:0] stringPool.Put(s) } }
2.使用sync.Pool
func Test_Pool(t *testing.Tjs) { dataSlice1 := demoData() dataSlice2 := demoData() dataSlice2[1] = "test4" fmt.Printf("dataSlice1:%v %p,dataSlice2:%v %p\n", dataSlice1, dataSlice1, dataSlice2, dataSlice2) } func demoData() []string { strsPtr := NewString() strs := *strsPtr defer func() { *strsPtr = strs PutString(strsPtr) }() strs = append(strs, "test1", "test2") return strs }
打印结果:dataSlice1:[test1 test4] 0xc0000a6400,dataSlice2:[test1 test4] 0xc0000a6400
可以看到两个slice地址相同,内部使用同一个地址的数组,导致两次获取的数据互相影响
3.解决方法1
func Test_Pool(t *testing.T) { dataSlice1 := demoData() dataSlice2 := demoData() dataSlice2[1] = "test4" fmt.Printf("dataSlice1:%v %p,dataSlice2:%v %p\n", dataSlice1, dataSlice1, dataSlice2, dataSlice2) } func demoDjavascriptata() []string { strsPtr := NewString() strs := *strsPtr defer func() { *strsPtr = strs PutString(strsPtr) }() strs = append(strs, "test1", 编程客栈"test2") // 深复制 var items = make([]string, len(strs)) copy(items, strs) return items }
使用深复制,在put回sync.Pool中之前把数据复制返回,但这样资源池失去了意义,获取到资源后有进行了一次内存的申请
4.解决方法2
我们看下golang语言源码怎么解决的
参考 go/src/fmt/print.go 302行 Fprintln方法
func Fprintln(w io.Writer, a ...any) (n int, err error) { p := newprinter() p.doPrintln(a) n, err = w.Write(p.buf) p.free() return }
可以看到306行有p.free()代码,newPrinter()和free()之间进行数据处理,数据处理完成之后再把资源返回给sync.Pool
总结
不是任何场景都适合用sync.Pool,需要关注并发情况下资源池中数据同步修改影响的问题。
到此这篇关于golang sync.Pool 指针数据覆盖问题解决的文章就介绍到这了,更多相关golang sync.Pool 指针覆盖内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论