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

Mat*_*rix 2 optimization performance concatenation go slice

现在我正在使用下面的代码(如同BenchmarkEncoder())并且速度很快,但我想知道是否有更快,更有效的方法.我用以下基准测试GOMAXPROCS=1:

sudo -E nice -n -20 go test -bench . -benchmem -benchtime 3s
Run Code Online (Sandbox Code Playgroud)

.

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)

    }
}
Run Code Online (Sandbox Code Playgroud)

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

icz*_*cza 5

bytes.Join()是非常快,但它做了一些额外的工作,在可追加的字节切片之间附加分隔符.即使分隔符为空或nil切片,它也会这样做.

因此,如果您关心最佳性能(虽然它会略有改进),您可以bytes.Join()在不附加(空)分隔符的情况下执行操作:分配足够大的字节切片,并使用内置的方法将每个切片复制到结果中copy()功能.

试试吧Go Playground:

func Join(s ...[]byte) []byte {
    n := 0
    for _, v := range s {
        n += len(v)
    }

    b, i := make([]byte, n), 0
    for _, v := range s {
        i += copy(b[i:], v)
    }
    return b
}
Run Code Online (Sandbox Code Playgroud)

使用它:

concatenated := Join(d1, d2, d3, d4)
Run Code Online (Sandbox Code Playgroud)

改进:

如果您事先知道总大小(或者您可以比在切片上循环更快地计算它),请提供它,您可以避免必须循环切片以计算所需的大小:

func JoinSize(size int, s ...[]byte) []byte {
    b, i := make([]byte, size), 0
    for _, v := range s {
        i += copy(b[i:], v)
    }
    return b
}
Run Code Online (Sandbox Code Playgroud)

在你的情况下使用它:

concatenated := JoinSize(48 + len(d4), d1, d2, d3, d4)
Run Code Online (Sandbox Code Playgroud)

笔记:

但是,如果你最终的目标是将连接的字节片写入a io.Writer,性能方面最好不要连接它们,而是分别将它们写入其中.