2018 년에 추가 된 메모
Go 1.10부터 strings.Builder
유형 이 있으므로 자세한 내용은이 답변을 참조하십시오 .
201x 이전 답변
@ cd1의 벤치 마크 코드 및 기타 답변이 잘못되었습니다. b.N
벤치 마크 기능으로 설정되어 있지 않아야합니다. 테스트 실행 시간이 안정적인지 확인하기 위해 go 테스트 도구에 의해 동적으로 설정됩니다.
벤치 마크 함수는 동일한 테스트 b.N
시간을 실행 해야하며 루프 내부의 테스트는 각 반복마다 동일해야합니다. 내부 루프를 추가하여 수정합니다. 또한 다른 솔루션에 대한 벤치 마크를 추가합니다.
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)
}
}
환경은 OS X 10.11.6, 2.2GHz Intel Core i7입니다.
시험 결과:
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
결론:
CopyPreAllocate
가장 빠른 방법입니다. AppendPreAllocate
No.1과 거의 비슷하지만 코드를 작성하는 것이 더 쉽습니다.
Concat
속도와 메모리 사용량 모두에서 성능이 실제로 떨어집니다. 사용하지 마십시오.
Buffer#Write
그리고 Buffer#WriteString
기본적으로 다니 - 브롬은 코멘트에서 밝혔다 @ 것과는 달리, 속도가 동일합니다. 고려는 string
참으로 []byte
그 의미가, 이동에.
- bytes.Buffer는 기본적으로
Copy
여분의 책 보관 및 기타 자료와 동일한 솔루션을 사용합니다 .
Copy
과 Append
, bytes.Buffer와 동일 (64)의 부트 스트랩 크기를 사용
Append
더 많은 메모리와 할당량을 사용하면 사용하는 증가 알고리즘과 관련이 있다고 생각합니다. 바이트만큼 빠른 메모리를 늘리지 않습니다.
암시:
- 이러한 영업 이익이 원하는 것을 같은 간단한 작업을 위해, 내가 사용하는 것
Append
또는AppendPreAllocate
합니다. 충분히 빠르고 사용하기 쉽습니다.
- 버퍼를 동시에 읽고 쓸 필요가 있다면
bytes.Buffer
물론 사용하십시오 . 그것이 설계된 것입니다.