字符串拼接

+
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

性能上提升还是很明显的