Created
February 24, 2021 11:22
-
-
Save itchyny/bcd4bbd6909d2db6f500c6b68934d134 to your computer and use it in GitHub Desktop.
Performance comparison of implementations of strings.Join
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"strings" | |
) | |
func main() {} | |
func JoinPlus(xs []string, sep string) string { | |
var ret string | |
for i, x := range xs { | |
if i > 0 { | |
ret += sep | |
} | |
ret += x | |
} | |
return ret | |
} | |
func JoinBytesBuffer(xs []string, sep string) string { | |
var buf bytes.Buffer | |
for i, x := range xs { | |
if i > 0 { | |
buf.WriteString(sep) | |
} | |
buf.WriteString(x) | |
} | |
return buf.String() | |
} | |
func JoinStringsBuilder(xs []string, sep string) string { | |
var sb strings.Builder | |
for i, x := range xs { | |
if i > 0 { | |
sb.WriteString(sep) | |
} | |
sb.WriteString(x) | |
} | |
return sb.String() | |
} | |
func JoinStringsBuilderGrow(xs []string, sep string) string { | |
if len(xs) == 0 { | |
return "" | |
} | |
size := len(sep) * (len(xs) - 1) | |
for _, x := range xs { | |
size += len(x) | |
} | |
var sb strings.Builder | |
sb.Grow(size) | |
for i, x := range xs { | |
if i > 0 { | |
sb.WriteString(sep) | |
} | |
sb.WriteString(x) | |
} | |
return sb.String() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"strconv" | |
"strings" | |
"testing" | |
) | |
var ( | |
xs []string | |
sep string | |
expected string | |
) | |
func init() { | |
xs = make([]string, 2000) | |
for i := range xs { | |
xs[i] = strconv.Itoa(i) | |
} | |
sep = ", " | |
expected = strings.Join(xs, sep) | |
} | |
func TestJoin(t *testing.T) { | |
if expected != JoinPlus(xs, sep) { | |
t.Error("JoinPlus(xs, sep)") | |
} | |
if expected != JoinBytesBuffer(xs, sep) { | |
t.Error("JoinBytesBuffer(xs, sep)") | |
} | |
if expected != JoinStringsBuilder(xs, sep) { | |
t.Error("JoinStringsBuilder(xs, sep)") | |
} | |
if expected != JoinStringsBuilderGrow(xs, sep) { | |
t.Error("JoinStringsBuilderGrow(xs, sep)") | |
} | |
} | |
func BenchmarkJoinPlus(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
JoinPlus(xs, sep) | |
} | |
} | |
func BenchmarkJoinBytesBuffer(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
JoinBytesBuffer(xs, sep) | |
} | |
} | |
func BenchmarkJoinStringsBuilder(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
JoinStringsBuilder(xs, sep) | |
} | |
} | |
func BenchmarkJoinStringsBuilderGrow(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
JoinStringsBuilderGrow(xs, sep) | |
} | |
} | |
func BenchmarkStringsJoin(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
strings.Join(xs, sep) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
❯ go test -bench . -benchmem | |
goos: darwin | |
goarch: amd64 | |
pkg: join-benchmark | |
cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz | |
BenchmarkJoinPlus-16 366 2961378 ns/op 21757467 B/op 3998 allocs/op | |
BenchmarkJoinBytesBuffer-16 40668 28744 ns/op 49584 B/op 10 allocs/op | |
BenchmarkJoinStringsBuilder-16 53319 22469 ns/op 48504 B/op 17 allocs/op | |
BenchmarkJoinStringsBuilderGrow-16 70018 17527 ns/op 12288 B/op 1 allocs/op | |
BenchmarkStringsJoin-16 68562 17164 ns/op 12288 B/op 1 allocs/op | |
PASS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment