Golang several string splicing methods

Recently, performance optimization is being done. There is a function that takes a long time. It seems that most of the operations inside are string splicing operations, and there are actually many implementations of string splicing in golang.

Implementation

1. Use operators directly

func BenchmarkAddStringWithOperator(b *testing.B) {
    hello := "hello"
    world := "world"
    for i := 0; i < b.N; i++ {
        _ = hello + "," + world
    }
}

The strings in golang are immutable. Every operation will generate a new string, so many temporary useless strings will be generated. Not only are they useless, they will also bring extra burden to gc, so performance comparison difference

2.fmt.Sprintf()

func BenchmarkAddStringWithSprintf(b *testing.B) {
    hello := "hello"
    world := "world"
    for i := 0; i < b.N; i++ {
        _ = fmt.Sprintf("%s,%s", hello, world)
    }
}

It is implemented internally by []byte, unlike direct operators that will generate many temporary strings, but the internal logic is more complicated, there are a lot of extra judgments, and interface is used, so the performance is not very good.

3.strings.Join()

func BenchmarkAddStringWithJoin(b *testing.B) {
    hello := "hello"
    world := "world"
    for i := 0; i < b.N; i++ {
        _ = strings.Join([]string{hello, world}, ",")
    }
}

Join will first calculate the length of a spliced ​​string based on the content of the string array, and then apply for the corresponding size of memory, fill in one string one by one, in the case of an array, this efficiency will be very high, but originally No, the cost of constructing this data is not small

4.buffer.WriteString()

func BenchmarkAddStringWithBuffer(b *testing.B) {
    hello := "hello"
    world := "world"
    for i := 0; i < 1000; i++ {
        var buffer bytes.Buffer
        buffer.WriteString(hello)
        buffer.WriteString(",")
        buffer.WriteString(world)
        _ = buffer.String()
    }
}

This is ideal. It can be used as a variable character and optimized for memory growth. If you can estimate the length of the string, you can also use the buffer.Grow() interface to set the capacity

Test Results

BenchmarkAddStringWithOperator-8            50000000             30.3 ns/op
BenchmarkAddStringWithSprintf-8             5000000              261  ns/op
BenchmarkAddStringWithJoin-8                30000000             58.7 ns/op
BenchmarkAddStringWithBuffer-8              2000000000           0.00 ns/op

This is the result of running on my own Mac, go version go version go1.8 darwin/amd64, this result is for reference only, it should be based on the actual production environment value, the code is at: https://github.com /hatlonely/hellogolang/blob/master/internal/buildin/string_test.go

main conclusion

  1. In the case of existing string arrays, the use  strings.Join() can have better performance
  2. In some occasions with higher performance requirements, try to use it  buffer.WriteString() to obtain better performance
  3. When performance requirements are not too high, directly use operators, the code is shorter and clearer, and better readability can be obtained
  4. If you need to splice not only strings, but also other needs such as numbers, you can consider fmt.Sprintf()

Reference link

Performance analysis of go language string concatenation:  http://herman.asia/efficient-string-concatenation-in-go

This article is reproduced from the short book article: Golang several string connection methods

Guess you like

Origin blog.csdn.net/feikillyou/article/details/112613565