字符串拼接
+
bytes.Buffer
strings.Builder
func BenchmarkStringConcat1(b *testing.B) {
s := ""
for i := 0; i < b.N; i++ {
s += "hello world"
}
}
func BenchmarkStringConcat2(b *testing.B) {
var buf bytes.Buffer
for i := 0; i < b.N; i++ {
buf.WriteString("hello world")
}
_ = buf.String()
}
func BenchmarkStringConcat3(b *testing.B) {
var sb strings.Builder
for i := 0; i < b.N; i++ {
sb.WriteString("hello world")
}
_ = sb.String()
}
> go test -bench=. -benchtime=100000x -benchmem
goos: windows
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
BenchmarkStringConcat1-8 100000 73067 ns/op 554013 B/op 1 allocs/op
BenchmarkStringConcat2-8 100000 19.38 ns/op 53 B/op 0 allocs/op
BenchmarkStringConcat3-8 100000 9.759 ns/op 52 B/op 0 allocs/op
PASS
ok test 7.358s
strings.Builder+
++
strings.Builderbytes.Buffer[]bytebytes.Bufferstrings.Builder[]byte
// bytes.Buffer
func (b *Buffer) String() string {
if b == nil {
// Special case, useful in debugging.
return "<nil>"
}
return string(b.buf[b.off:])
}
// strings.Builder
func (b *Builder) String() string {
return unsafe.String(unsafe.SliceData(b.buf), len(b.buf))
}
// String returns a string value whose underlying bytes
// start at ptr and whose length is len.
//
// The len argument must be of integer type or an untyped constant.
// A constant len argument must be non-negative and representable by a value of type int;
// if it is an untyped constant it is given type int.
// At run time, if len is negative, or if ptr is nil and len is not zero,
// a run-time panic occurs.
//
// Since Go strings are immutable, the bytes passed to String
// must not be modified afterwards.
func String(ptr *byte, len IntegerType) string
字符串与切片转换
unsafe
type StringHeader struct {
Data uintptr
Len int
}
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
1、字符串转换成切片
func BenchmarkStringToByte1(b *testing.B) {
s := "hello world"
for i := 0; i < b.N; i++ {
s2b1(s)
}
}
func s2b1(s string) []byte {
return []byte(s)
}
func BenchmarkStringToByte2(b *testing.B) {
s := "hello world"
for i := 0; i < b.N; i++ {
s2b2(s)
}
}
func s2b2(s string) (b []byte) {
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh.Data = sh.Data
bh.Len = sh.Len
bh.Cap = sh.Len
return
}
> go test -bench=BenchmarkStringToByte -benchtime=10000000x -benchmem
goos: windows
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
BenchmarkStringToByte1-8 10000000 4.904 ns/op 0 B/op 0 allocs/op
BenchmarkStringToByte2-8 10000000 0.2929 ns/op 0 B/op 0 allocs/op
2、切片转换成字符串
func BenchmarkByteToString1(b *testing.B) {
bb := []byte(`hello world`)
for i := 0; i < b.N; i++ {
b2s1(bb)
}
}
func b2s1(b []byte) string {
return string(b)
}
func BenchmarkByteToString2(b *testing.B) {
bb := []byte(`hello world`)
for i := 0; i < b.N; i++ {
b2s2(bb)
}
}
func b2s2(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
> go test -bench=BenchmarkByteToString -benchtime=10000000x -benchmem
goos: windows
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
BenchmarkByteToString1-8 10000000 6.078 ns/op 0 B/op 0 allocs/op
BenchmarkByteToString2-8 10000000 0.2929 ns/op 0 B/op 0 allocs/op
性能上提升还是很明显的