登录
首页 >  Golang >  Go问答

突如其来的同步池分配

来源:stackoverflow

时间:2024-03-01 13:15:25 416浏览 收藏

编程并不是一个机械性的工作,而是需要有思考,有创新的工作,语法是固定的,但解决问题的思路则是依靠人的思维,这就需要我们坚持学习和更新自己的知识。今天golang学习网就整理分享《突如其来的同步池分配》,文章讲解的知识点主要包括,如果你对Golang方面的知识点感兴趣,就不要错过golang学习网,在这可以对大家的知识积累有所帮助,助力开发能力的提升。

问题内容

all,学习golang一个月了,遇到了这个问题。基本上我正在尝试重用sync.pool中的[]字节来进行一些哈希处理。

我添加了一个最小可行的示例来重现它:

type mwriter struct {
    pool *sync.pool
}

func (m *mwriter) writespan(span interface{}) {
    haha := m.pool.get().([]byte)
    // in real code some actions here instead of simply setting haha[0] = 1
    haha[0] = 1
    m.pool.put(haha)
}

func newwriter() *mwriter {
    bytepool := &sync.pool{
        new: func() interface{} {
            return make([]byte, 16)
        },
    }
    return &mwriter{
        pool: bytepool,
    }
}

func benchmark_writespan(b *testing.b) {
    c := newwriter()

    b.resettimer()
    b.reportallocs()
    for it := 0; it < b.n; it++ {
        c.writespan(nil)
    }
}

根据我的印象,sync.pool 不会为 []byte 分配新内存,但我在这里看到 m.pool.get() 进行了额外的分配。

benchmark_writespan-12 30000000 47.6 ns/op 32 b/op 1 分配/操作 经过

这背后的解释是什么?我还在这里尝试了一些更简单的基准测试:

func benchmark_2(b *testing.b) {
    // initializing pool
    pool := &sync.pool{
        new: func() interface{} {
            return make([]byte, 4)
        },
    }
    b.resettimer()
    b.reportallocs()
    // get hold of instance one
    one := pool.get().([]byte)
    one[1] = 1
    one[2] = 2
    // submit back the instance after using
    pool.put(one)
}

但这显示没有分配:

benchmark_2-12 2000000000 0.00 ns/op 0 b/op 0 分配/操作

感谢这里的任何帮助! (如果这不是sync.pool的使用方式,有什么建议吗?)

已编辑:

好的,我在 writespan 基准测试中添加了一个简单的循环,现在它给出了以下基准测试:

func benchmark_writespan(b *testing.b) {
    c := newwriter()

    b.resettimer()
    b.reportallocs()
    for it := 0; it < b.n; it++ {
        for i := 0; i < 5; i++ {
            c.writespan(nil)
        }
    }
}

benchmark_writespan-12 5000000 226 ns/操作 160 b/操作 5 分配/操作

看起来池在每次写入时分配 32b,难道它不应该在第一次获取后重用相同的 byte[] 吗?

更新 @jimb我确实在实际代码中有一些逻辑可以更新字节切片和哈希值。像下面这样:

byteSlice := ds.poolInstance.bytepool.Get().([]byte)
    copy(byteSlice[:len(ds.hashSalt)], ds.hashSalt)
    span.TraceID.MarshalTo(byteSlice[len(ds.hashSalt):])
    hashVal := ds.hashBytes(byteSlice) 
    ds.poolInstance.bytepool.Put(byteSlice)

我不确定这是否算作作为短期对象的一部分维护的空闲列表,您能否更具体地说明这一点?


解决方案


我想我找到了背后的原因。在我的真实代码中,我曾经有:

bytepool: &sync.pool{
    new: func() interface{} {
        return make([]byte, length)
    },
},
...
...
bytepool.get().([]byte)

不知何故,当我将其更改为

bytepool: &sync.Pool{
    New: func() interface{} {
        byteP := make([]byte, length)
        return &byteP
    },
},
...
...
bytepool.Get().(*[]byte)

分配下降到 0。很抱歉,大家看起来不是sync.pool 的问题,而是底层数据结构的问题。不过还是感谢您的评论!

以上就是《突如其来的同步池分配》的详细内容,更多关于的资料请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>