将几个 []byte 连接在一起的最快方法是什么?

现在我正在使用下面的代码(如 中所示BenchmarkEncoder())并且速度很快,但我想知道是否有更快、更有效的方法。我用GOMAXPROCS=1和作为基准:


sudo -E nice -n -20 go test -bench . -benchmem -benchtime 3s

.


package blackbird


import (

    "testing"

    "encoding/hex"

    "log"

    "bytes"

    "encoding/json"

)


var (

    d1, d2, d3, d4, outBytes []byte

    toEncode [][]byte

)


func init() {

    var err interface{}

    d1, err = hex.DecodeString("6e5438fd9c3748868147d7a4f6d355dd")

    d2, err = hex.DecodeString("0740e2dfa4b049f2beeb29cc304bdb5f")

    d3, err = hex.DecodeString("ab6743272358467caff7d94c3cc58e8c")

    d4, err = hex.DecodeString("7411c080762a47f49e5183af12d87330e6d0df7dd63a44808db4e250cdea0a36182fce4a309842e49f4202eb90184dd5b621d67db4a04940a29e981a5aea59be")

    if err != nil {

        log.Fatal("hex decoding failed: %v", err)

    }

    toEncode = [][]byte{d1, d2, d3, d4}


}


func Encode(stuff [][]byte) []byte {

    return bytes.Join(stuff, nil)

}


func BenchmarkEncoderDirect(b *testing.B) {

    for i := 0; i < b.N; i++ {

        bytes.Join(toEncode, nil)

    }

}


func BenchmarkEncoder(b *testing.B) {

    for i := 0; i < b.N; i++ {

        Encode(toEncode)

    }

}


func BenchmarkJsonEncoder(b *testing.B) {

    for i := 0; i < b.N; i++ {

        outBytes, _ = json.Marshal(toEncode)


    }

}

将多个连接[]byte在一起的最快方法是什么?


开满天机
浏览 505回答 2
2回答

jeck猫

bytes.Join()非常快,但它做了一些额外的工作,在可附加的字节片之间附加分隔符。即使分隔符为空或nil切片,它也会这样做。因此,如果您关心最佳性能(尽管它会略有改进),您可以bytes.Join()在不附加(空)分隔符的情况下执行以下操作:分配一个足够大的字节切片,并使用内置的将每个切片复制到结果中copy()功能。在Go Playground上试试:func Join(s ...[]byte) []byte {&nbsp; &nbsp; n := 0&nbsp; &nbsp; for _, v := range s {&nbsp; &nbsp; &nbsp; &nbsp; n += len(v)&nbsp; &nbsp; }&nbsp; &nbsp; b, i := make([]byte, n), 0&nbsp; &nbsp; for _, v := range s {&nbsp; &nbsp; &nbsp; &nbsp; i += copy(b[i:], v)&nbsp; &nbsp; }&nbsp; &nbsp; return b}使用它:concatenated := Join(d1, d2, d3, d4)改进:如果您事先知道总大小(或者您可以比循环切片更快地计算它),提供它,您可以避免必须循环切片以计算所需的大小:func JoinSize(size int, s ...[]byte) []byte {&nbsp; &nbsp; b, i := make([]byte, size), 0&nbsp; &nbsp; for _, v := range s {&nbsp; &nbsp; &nbsp; &nbsp; i += copy(b[i:], v)&nbsp; &nbsp; }&nbsp; &nbsp; return b}在您的情况下使用它:concatenated := JoinSize(48 + len(d4), d1, d2, d3, d4)笔记:但是,如果您最终的目标是将连接的字节切片写入一个io.Writer,性能方面最好不要连接它们,而是将每个切片单独写入。

慕标5832272

总的来说,@icza 的回答是正确的。但是,对于您的特定用例,您可以分配一次并更有效地解码到该缓冲区:像这样:package mainimport (&nbsp; &nbsp; "encoding/hex")func main() {&nbsp; &nbsp; h1 := []byte("6e5438fd9c3748868147d7a4f6d355dd")&nbsp; &nbsp; h2 := []byte("0740e2dfa4b049f2beeb29cc304bdb5f")&nbsp; &nbsp; h3 := []byte("ab6743272358467caff7d94c3cc58e8c")&nbsp; &nbsp; h4 := []byte("7411c080762a47f49e5183af12d87330e6d0df7dd63a44808db4e250cdea0a36182fce4a309842e49f4202eb90184dd5b621d67db4a04940a29e981a5aea59be")&nbsp; &nbsp; tg := make([]byte, 16+16+16+(1024*1024)) // allocate enough space for the 3 IDs and a max 1MB of extra data&nbsp; &nbsp; hex.Decode(tg[:16], h1)&nbsp; &nbsp; hex.Decode(tg[16:32], h2)&nbsp; &nbsp; hex.Decode(tg[32:48], h3)&nbsp; &nbsp; l, _ := hex.Decode(tg[48:], h4)&nbsp; &nbsp; tg = tg[:48+l]}在该代码的末尾,tg保存 3 个 ID 加上可变长度的第 4 个数据块,连续解码。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go