2016-09-04 7 views
1

未知の量のデータをバイトのスライスに追加する必要がある状況では、ループ内で組み込み関数append()を使用するか、新しいBufferを作成することができますWrite()機能を使用してください。Builtin append with bytes.Buffer write

どの方法が最速ですか?以下のベンチマークによって示されるように、組み込み関数appendを使用して

+0

組み込み関数は、任意の代替よりも一般的に高速です。私は追加がこの場合にはより速くなると思います – Sridhar

答えて

2

それはケースを使用することによって決まります。
どちらの場合もbytes.Bufferappend(サンプル:1,2,3,4)より高速です。

buf = append(buf, make([]byte, 16)...)6.6623811sを取る使用して、buf.Write(make([]byte, 16))4.6482659sを取る
を使用します。サンプル5、6のために


buf = append(buf, byte(i))を使用すると、445.0255msをとり、
buf.WriteByte(byte(i))を使用すると、組み込み関数copyを使用し、それが高速です1.4410824s


そしてbytes.Bufferを取ります

//書き込みpの内容をバッファに追加し、バッファを増やす をとします。 //必要です。戻り値nはpの長さです。エラーは常に です。
//バッファが大きくなりすぎると、書き込みは 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.8892797sをとり、append 7をとります。7514434s

は、これらのベンチマークを参照してくださいappendを使用

1-:

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)) 
} 

出力:bytes.Buffer

を使用

7.7514434s 
1600000000 

2-

出力:bytes.Bufferを使用

4.8892797s 
1600000000 

3- make([]byte, 16)有する:appendを使用

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- make([]byte, 16)有する:

を使用して3210

5- 445.0255msかかり:

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 
} 

および参照:

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かかり

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

+0

2つの答えから異なる結果を見て、自分のニーズに応じて自分自身を作成し​​ようとしました:https://play.golang.org/p/kyuX5qzaIG。結果はappendが最も速いことを示します(append = 2.70 ns/op、bufferWrite = 9.32 ns/op)。何とかベンチに問題があるはずです。 –

+0

@WilliamPoussier:Tim Cooperのfunc: 'randomSlice'での返答' return byte(0)、rand.Intn()の代わりにreturn make([]バイト、rand.Intn(1 << 10) 1 << 10)) '長さがゼロのスライスを使用すると良いベンチマークではありません。 –

+1

本当にあなたは正しいです。私がテストデータによって空でないスライスに変更したとき、appendはバッファを使うよりも遅いです。 –

1

は、高速です:

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