前言
Go
string类型
Gostring
// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
// not nil. Values of string type are immutable.
type string string
string8
string
type stringStruct struct {
str unsafe.Pointer
len int
}
stringStructslicestrlenslice
//go:nosplit
func gostringnocopy(str *byte) string {
ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
s := *(*string)(unsafe.Pointer(&ss))
return s
}
bytestringbyte
stringbyteGostringGostring
stringstringStructstrgc
string
字符串拼接的6种方式及原理
原生拼接方式"+"
Go+
var s string
s += "asong"
s += "真帅"
+
fmt.Sprintf
Gofmt.Sprintf
str := "asong"
str = fmt.Sprintf("%s%s", str, str)
fmt.Sprintf
Strings.builder
Gostringsstrings.BuilderwriteString
var builder strings.Builder
builder.WriteString("asong")
builder.String()
strings.builder
type Builder struct {
addr *Builder // of receiver, to detect copies by value
buf []byte // 1
}
addrcopycheckbufbytewriteString()buf
func (b *Builder) WriteString(s string) (int, error) {
b.copyCheck()
b.buf = append(b.buf, s...)
return len(s), nil
}
String[]]bytestring
func (b *Builder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}
bytes.Buffer
stringbyteGobytes.Bufferbytes.Bufferbytebyte
buf := new(bytes.Buffer)
buf.WriteString("asong")
buf.String()
bytes.buffer[]byte
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
lastRead readOp // last read operation, so that Unread* can work correctly.
}
bytes.BufferBufferBufferoffcapWriteString
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(len(s))
if !ok {
m = b.grow(len(s))
}
return copy(b.buf[m:], s), nil
}
slicecopycopy
[]bytestring
func (b *Buffer) String() string {
if b == nil {
// Special case, useful in debugging.
return "<nil>"
}
return string(b.buf[b.off:])
}
strings.join
Strings.joinstring
baseSlice := []string{"asong", "真帅"}
strings.Join(baseSlice, "")
strings.joinstrings.builder
func Join(elems []string, sep string) string {
switch len(elems) {
case 0:
return ""
case 1:
return elems[0]
}
n := len(sep) * (len(elems) - 1)
for i := 0; i < len(elems); i++ {
n += len(elems[i])
}
var b Builder
b.Grow(n)
b.WriteString(elems[0])
for _, s := range elems[1:] {
b.WriteString(sep)
b.WriteString(s)
}
return b.String()
}
joinb.Grow(n)
append
stringbyteappend
buf := make([]byte, 0)
base = "asong"
buf = append(buf, base...)
string(base)
[]bytestring
Benchmark对比
GoBenchmark
少量字符串拼接
大量字符串拼接
github
我们先定义一个基础字符串:
var base = "123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASFGHJKLZXCVBNM"
少量字符串拼接的测试我们就采用拼接一次的方式验证,base拼接base,因此得出benckmark结果:
goos: darwin
goarch: amd64
pkg: asong.cloud/Golang_Dream/code_demo/string_join/once
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkSumString-16 21338802 49.19 ns/op 128 B/op 1 allocs/op
BenchmarkSprintfString-16 7887808 140.5 ns/op 160 B/op 3 allocs/op
BenchmarkBuilderString-16 27084855 41.39 ns/op 128 B/op 1 allocs/op
BenchmarkBytesBuffString-16 9546277 126.0 ns/op 384 B/op 3 allocs/op
BenchmarkJoinstring-16 24617538 48.21 ns/op 128 B/op 1 allocs/op
BenchmarkByteSliceString-16 10347416 112.7 ns/op 320 B/op 3 allocs/op
PASS
ok asong.cloud/Golang_Dream/code_demo/string_join/once 8.412s
大量字符串拼接的测试我们先构建一个长度为200的字符串切片:
var baseSlice []string
for i := 0; i < 200; i++ {
baseSlice = append(baseSlice, base)
}
benchmark
goos: darwin
goarch: amd64
pkg: asong.cloud/Golang_Dream/code_demo/string_join/muliti
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkSumString-16 7396 163612 ns/op 1277713 B/op 199 allocs/op
BenchmarkSprintfString-16 5946 202230 ns/op 1288552 B/op 600 allocs/op
BenchmarkBuilderString-16 262525 4638 ns/op 40960 B/op 1 allocs/op
BenchmarkBytesBufferString-16 183492 6568 ns/op 44736 B/op 9 allocs/op
BenchmarkJoinstring-16 398923 3035 ns/op 12288 B/op 1 allocs/op
BenchmarkByteSliceString-16 144554 8205 ns/op 60736 B/op 15 allocs/op
PASS
ok asong.cloud/Golang_Dream/code_demo/string_join/muliti 10.699s
结论
benchmark
++fmt.Sprintfstrings.BuilderGostrings.builderstrings.builderGrowstrings.joingrowstrings.builderbytes.Bufferstrings.builderbytes.Bufferstrings.buidler[]byte
同步最后分析的结论:
strings.buildergrowstrings.joinstrings.builder+strings.builder
综合对比性能排序:
strings.join` ≈ `strings.builder` > `bytes.buffer` > `[]byte`转换`string` > "+" > `fmt.sprintf
总结
6benckmarkstrings.builder+
- END -
本文转载自阿松的公众号,喜欢文章的欢迎关注后续的持续更新。