内置追加与bytes.Buffer写

时间:2016-09-04 16:22:32

标签: performance go byte buffer

在我需要向一个字节片段添加未知数量的数据的情况下,让我们说在循环中,我可以使用内置函数someparameter或创建一个新的append()并使用Buffer函数。

哪种方法最快?

2 个答案:

答案 0 :(得分:2)

这取决于用例。
在这两种情况下,bytes.Buffer都比append快(样本:1,2,3,4)。

使用buf.Write(make([]byte, 16))需要4.6482659s
使用buf = append(buf, make([]byte, 16)...)需要6.6623811s

对于样品5,6:
使用buf = append(buf, byte(i))需要445.0255ms
使用buf.WriteByte(byte(i))需要1.4410824s

并且bytes.Buffer使用内置函数copy并且速度很快:

  

// Write将p的内容追加到缓冲区,增加缓冲区   作为
  //需要返回值n是p的长度;总是错的   零。如果是   //缓冲区变得太大,Write会惊慌失措   ErrTooLarge。

func (b *Buffer) Write(p []byte) (n int, err error) {
  b.lastRead = opInvalid
  m := b.grow(len(p))
  return copy(b.buf[m:], p), nil
}

bytes.Buffer需要4.8892797,append需要7.7514434s

请参阅以下基准:

1-使用append

package main

import (
    "fmt"
    "time"
)

func main() {
    buf := []byte{}
    data := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    t := time.Now()
    for i := 0; i < 100000000; i++ {
        buf = append(buf, data...)
    }
    fmt.Println(time.Since(t))
    fmt.Println(len(buf))
}

输出:

7.7514434s
1600000000

2-使用bytes.Buffer

package main

import (
    "bytes"
    "fmt"
    "time"
)

func main() {
    buf := &bytes.Buffer{}
    data := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    t := time.Now()
    for i := 0; i < 100000000; i++ {
        buf.Write(data)
    }
    fmt.Println(time.Since(t))
    fmt.Println(buf.Len())
}

输出:

4.8892797s
1600000000

3-将bytes.Buffermake([]byte, 16)一起使用:

package main

import (
    "bytes"
    "fmt"
    "time"
)

func main() {
    buf := &bytes.Buffer{}
    t := time.Now()
    for i := 0; i < 100000000; i++ {
        buf.Write(make([]byte, 16))
    }
    fmt.Println(time.Since(t)) // 4.6482659s
    fmt.Println(buf.Len())     //1600000000
}

4-将appendmake([]byte, 16)一起使用:

package main

import (
    "fmt"
    "time"
)

func main() {
    buf := []byte{}
    t := time.Now()
    for i := 0; i < 100000000; i++ {
        buf = append(buf, make([]byte, 16)...)
    }
    fmt.Println(time.Since(t)) // 6.6623811s
    fmt.Println(len(buf))      // 1600000000
}

5-使用buf = append(buf, byte(i))需要445.0255ms

package main

import (
    "fmt"
    "time"
)

func main() {
    buf := []byte{}
    t := time.Now()
    for i := 0; i < 100000000; i++ {
        buf = append(buf, byte(i))
    }
    fmt.Println(time.Since(t)) // 445.0255ms
    fmt.Println(len(buf))      // 100000000
}

6-使用buf.WriteByte(byte(i))需要1.4410824s

package main

import (
    "bytes"
    "fmt"
    "time"
)

func main() {
    buf := &bytes.Buffer{}

    t := time.Now()
    for i := 0; i < 100000000; i++ {
        buf.WriteByte(byte(i))
    }
    fmt.Println(time.Since(t)) // 1.4410824s
    fmt.Println(buf.Len())     // 100000000
}

见:

Appending to slice bad performance.. why?
Where is append() implementation?
Efficient appending to a variable-length container of strings (Golang)

答案 1 :(得分:1)

使用内置函数append更快,如以下基准所示:

package x

import (
    "bytes"
    "math/rand"
    "testing"
    "time"
)

var startSeed = time.Now().UnixNano()

func randomSlice() []byte {
    return make([]byte, 0, rand.Intn(1<<10))
}

func BenchmarkAppend(b *testing.B) {
    rand.Seed(startSeed)
    b.ResetTimer()
    var all []byte

    for i := 0; i < b.N; i++ {
        all = append(all, randomSlice()...)
    }
}

func BenchmarkBufferWrite(b *testing.B) {
    rand.Seed(startSeed)
    b.ResetTimer()
    var buff bytes.Buffer
    for i := 0; i < b.N; i++ {
        buff.Write(randomSlice())
    }
    all := buff.Bytes()
    _ = all
}

结果:

BenchmarkAppend-4           10000000           206 ns/op         540 B/op          0 allocs/op
BenchmarkBufferWrite-4      10000000           214 ns/op         540 B/op          0 allocs/op