4

Golang performance benchmark and deep into the middle code: a string operation e...

 1 year ago
source link: https://songrgg.github.io/programming/golang-performance-benchmark-middle-code/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Golang performance benchmark and deep into the middle code: a string operation example
Posted 2 days agoUpdated 2 days agoprogramming4 minutes read (About 538 words)

Golang performance benchmark and deep into the middle code: a string operation example

Context

Recently, I’m looking for efficient string manipulation in Golang, during the process of that, I used Golang benchmark to test the execution time and checked the Golang middle code to know the underlying mechanism between different solutions.

The problem

Given a long string, replace the given character with the other given character in it and return the new string.

For example, the string is “aaaaaa”, replace “a” with “b”, after replacement, the return string will be “bbbbbb”.

All the following code can be found at Github Gist.

Solution 1: string concatenation

func replaceChar1(str string, ch, replaceCh byte) string {
var result string
for i := 0; i < len(str); i++ {
if str[i] == ch {
result = result + string(replaceCh)
} else {
result = result + string(result[i])
}
}
return result
}

Solution 2: Byte array

func replaceChar2(str string, ch, replaceCh byte) string {
bytes := []byte(str)
for i := 0; i < len(str); i++ {
if bytes[i] == ch {
bytes[i] = replaceCh
}
}
return string(bytes)
}

Solution 3: String builder

func replaceChar3(str string, ch, replaceCh byte) string {
var strBuilder strings.Builder
strBuilder.Grow(len(str))

for i := 0; i < len(str); i++ {
if str[i] == ch {
strBuilder.WriteByte(replaceCh)
} else {
strBuilder.WriteByte(str[i])
}
}
return strBuilder.String()
}

Performance Comparison

With 3 solutions right now, I want to know which one is more efficient, Golang benchmark is a good way of comparing the operation efficiency of these.

  1. Add a test file with _test suffix
  2. Add functions with Benchmark as prefix like
func BenchmarkStringReplace1(b *testing.B) {
// generate a 100,000-long string
n := 100_000
str := generateString(n)

// reset the timer to remove the execution time of generateString(100_000)
b.ResetTimer()
for i := 0; i < b.N; i++ {
replaceChar1(str, 'a', 'b')
}
}
  1. Run the benchmark
    The benchmark function must run the target code b.N times. During benchmark execution, b.N is adjusted until the benchmark function lasts long enough to be timed reliably.
$ go test -bench=. string_op_benchmark.go string_op_benchmark_test.go
goos: darwin
goarch: arm64
BenchmarkStringReplace1-10 3 389948722 ns/op
BenchmarkStringReplace2-10 18235 62494 ns/op
BenchmarkStringReplace3-10 5534 217069 ns/op

The output means that the loop BenchmarkStringReplace1-10 ran 3 times at a speed of 389948722 ns per loop.

The BenchmarkStringReplace2 behaved the best and BenchmarkStringReplace1-10 (String concatenation) behaved the worst.

One step further

What if I’m still curious about the behind scene of the code? I want to know what replaceChar2 did and the middle code it executed. The following command will generate the middle code of the replaceChar2 function.

$ GOSSAFUNC=replaceChar2 go build string_op_benchmark.go
# command-line-arguments
dumped SSA to ./ssa.html

Open the ssa.html, we can see the original code of replaceChar2 and its middle code, like

bytes := []byte(str) is mapped to runtime.stringtoslicebyte, return string(bytes) is mapped to runtime.slicebytetostring

SSA

If we want to make the string operation faster, we might reduce the memory copy or find the other operations we can eliminate.

Reference

facebook sharing button Share
twitter sharing button Tweet
pinterest sharing button Pin
email sharing button Email
sharethis sharing button Share

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK