场景
1. sync.Pool设置
- var stringPool = sync.Pool{
- New: func() any {
- return new([]string)
- },
- }
- func NewString() *[]string {
- v := stringPool.Get().(*[]string)
- return v
- }
- func PutString(s *[]string) {
- if s == nil {
- return
- }
- if cap(*s) > 2048 {
- s = nil
- } else {
- *s = (*s)[:0]
- stringPool.Put(s)
- }
- }
复制代码 2.使用sync.Pool
- 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 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 demoData() []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 指针覆盖内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
来源:互联网
免责声明:如果侵犯了您的权益,请联系站长(1277306191@qq.com),我们会及时删除侵权内容,谢谢合作! |
|