亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在 golang 中重用 slice with sync.Pool?

如何在 golang 中重用 slice with sync.Pool?

Go
富國滬深 2023-01-03 11:17:42
考慮這段代碼:type TestStruct struct {    Name string}func TestSliceWithPool(t *testing.T) {    var slicePool = sync.Pool{        New: func() interface{} {            t.Log("i am created")            s := make([]interface{}, 0)            return s        },    }    s, _ := slicePool.Get().([]interface{})    t.Logf("Lenth: %d, Cap: %d, Pointer: %p", len(s), cap(s), s)    for i := 0; i < 9000; i++ {        st := &TestStruct{Name: "test"}        s = append(s, st)    }    for _, v := range s {        if value, ok := v.(TestStruct); ok {            if value.Name != "test" {                t.Error("u are changed!")            }        }    }    s = s[:0]    slicePool.Put(s)    s2, _ := slicePool.Get().([]interface{})    t.Logf("Lenth: %d, Cap: %d, Pointer: %p", len(s), cap(s), s)    for i := 0; i < 8000; i++ {        st := &TestStruct{Name: "test2"}        s2 = append(s2, st)    }    for _, v := range s2 {        if value, ok := v.(TestStruct); ok {            if value.Name != "test2" {                t.Error("u are changed!")            }        }    }    slicePool.Put(s2)}測試結果為:slice_test.go:63: i am createdslice_test.go:70: Lenth: 0, Cap: 0, Pointer: 0x1019598slice_test.go:86: Lenth: 0, Cap: 9728, Pointer: 0xc000500000為什么只生成一次,地址卻不同?為什么上限是 9728?像這樣使用同一個切片有什么問題嗎?
查看完整描述

1 回答

?
斯蒂芬大帝

TA貢獻1827條經驗 獲得超8個贊

為什么只生成一次,地址卻不同?

因為在第一個 for 循環中,您將其追加到它的容量之外,它的 inNew設置為零,并將 的結果重新分配給它append。詳見:為什么append()會修改提供的切片?(見例子)

像這樣使用同一個切片有什么問題嗎?

可能有。當您使用 reslicess = s[:0],您重置的是長度而不是容量。后備數組與之前的附加和重新分配操作中的相同。

因此,如果您再次追加到s2,容量將足以不會導致重新分配,并且您最終將覆蓋后備數組的第一個元素:

一個示范性的例子:

func TestSliceWithPool(t *testing.T) {

    var slicePool = sync.Pool{

        New: func() interface{} {

            t.Log("Created")

            s := make([]interface{}, 0)

            return s

        },

    }


    s, _ := slicePool.Get().([]interface{})

    for i := 0; i < 10; i++ {

        s = append(s, i)

    }

    fmt.Println(s) 

    // ^ output: [0 1 2 3 4 5 6 7 8 9]


    s = s[:0]

    slicePool.Put(s)


    s2, _ := slicePool.Get().([]interface{})

    fmt.Println(s)

    // ^ output: []


    for i := 0; i < 5; i++ {

        s2 = append(s2, i*10)

    }

    fmt.Println(s2) 

    // ^ output: [0 10 20 30 40]


    fmt.Println(s2[:10])

    // ^ output: [0 10 20 30 40 5 6 7 8 9]

}

這可能沒問題,因為你現在有一個擴展容量的切片,不需要在追加時重新分配,但如果你的應用程序保持其他切片頭指向相同的支持數組(如s和s2),從而防止緩沖區的垃圾收集。


查看完整回答
反對 回復 2023-01-03
  • 1 回答
  • 0 關注
  • 131 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號