2018'de not eklendi
Go 1.10'dan bir strings.Buildertür var, lütfen daha fazla ayrıntı için bu cevaba bir göz atın .
201x öncesi cevap
@ Cd1 ve diğer yanıtların karşılaştırma kodu yanlış. b.Nkarşılaştırmalı değerlendirme işlevinde ayarlanmamış olması gerekir. Testin yürütme süresinin kararlı olup olmadığını belirlemek için go test aracı tarafından dinamik olarak ayarlanır.
Bir kıyaslama işlevi aynı test b.Nsürelerini çalıştırmalı ve döngü içindeki test her yineleme için aynı olmalıdır. Bu yüzden bir iç döngü ekleyerek düzeltirim. Ayrıca diğer bazı çözümler için kıyaslamalar da ekliyorum:
package main
import (
"bytes"
"strings"
"testing"
)
const (
sss = "xfoasneobfasieongasbg"
cnt = 10000
)
var (
bbb = []byte(sss)
expected = strings.Repeat(sss, cnt)
)
func BenchmarkCopyPreAllocate(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
bs := make([]byte, cnt*len(sss))
bl := 0
for i := 0; i < cnt; i++ {
bl += copy(bs[bl:], sss)
}
result = string(bs)
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
func BenchmarkAppendPreAllocate(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
data := make([]byte, 0, cnt*len(sss))
for i := 0; i < cnt; i++ {
data = append(data, sss...)
}
result = string(data)
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
func BenchmarkBufferPreAllocate(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
buf := bytes.NewBuffer(make([]byte, 0, cnt*len(sss)))
for i := 0; i < cnt; i++ {
buf.WriteString(sss)
}
result = buf.String()
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
func BenchmarkCopy(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
data := make([]byte, 0, 64) // same size as bootstrap array of bytes.Buffer
for i := 0; i < cnt; i++ {
off := len(data)
if off+len(sss) > cap(data) {
temp := make([]byte, 2*cap(data)+len(sss))
copy(temp, data)
data = temp
}
data = data[0 : off+len(sss)]
copy(data[off:], sss)
}
result = string(data)
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
func BenchmarkAppend(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
data := make([]byte, 0, 64)
for i := 0; i < cnt; i++ {
data = append(data, sss...)
}
result = string(data)
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
func BenchmarkBufferWrite(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
var buf bytes.Buffer
for i := 0; i < cnt; i++ {
buf.Write(bbb)
}
result = buf.String()
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
func BenchmarkBufferWriteString(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
var buf bytes.Buffer
for i := 0; i < cnt; i++ {
buf.WriteString(sss)
}
result = buf.String()
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
func BenchmarkConcat(b *testing.B) {
var result string
for n := 0; n < b.N; n++ {
var str string
for i := 0; i < cnt; i++ {
str += sss
}
result = str
}
b.StopTimer()
if result != expected {
b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
}
}
Ortam OS X 10.11.6, 2.2 GHz Intel Core i7'dir
Test sonuçları:
BenchmarkCopyPreAllocate-8 20000 84208 ns/op 425984 B/op 2 allocs/op
BenchmarkAppendPreAllocate-8 10000 102859 ns/op 425984 B/op 2 allocs/op
BenchmarkBufferPreAllocate-8 10000 166407 ns/op 426096 B/op 3 allocs/op
BenchmarkCopy-8 10000 160923 ns/op 933152 B/op 13 allocs/op
BenchmarkAppend-8 10000 175508 ns/op 1332096 B/op 24 allocs/op
BenchmarkBufferWrite-8 10000 239886 ns/op 933266 B/op 14 allocs/op
BenchmarkBufferWriteString-8 10000 236432 ns/op 933266 B/op 14 allocs/op
BenchmarkConcat-8 10 105603419 ns/op 1086685168 B/op 10000 allocs/op
Sonuç:
CopyPreAllocateen hızlı yoldur; AppendPreAllocateNo.1'e oldukça yakın, ancak kodu yazmak daha kolay.
Concathem hız hem de bellek kullanımı için gerçekten kötü bir performansa sahip. Kullanma.
Buffer#Writeve Buffer#WriteString@ Dani-Br'nin yorumda söylediklerinin aksine, temel olarak hızda aynı. Düşünüldüğünde stringgerçekten de []bytemantıklı, Go.
- Tampon temel olarak
Copyekstra kitap tutma ve diğer şeylerle aynı çözümü kullanır .
Copyve Appendbaytlarla aynı 64 olan bir bootstrap boyutu kullanın.
Appenddaha fazla bellek ve alaşım kullanın, bence kullandığımız büyüme algoritmasıyla ilgili. Belleği bayt kadar hızlı büyütmüyor.
Öneri:
- OP'nin istediği gibi basit görevler için,
Appendya da kullanacağım AppendPreAllocate. Yeterince hızlı ve kullanımı kolaydır.
- Aynı anda tamponu okumak ve yazmak gerekirse
bytes.Buffer, elbette kullanın . Bunun için tasarlandı.