Last active
February 26, 2020 09:23
-
-
Save montanaflynn/58df9a48e40baca8dcdc to your computer and use it in GitHub Desktop.
String concatenation benchmarks in Golang inspired by https://www.reddit.com/r/golang/comments/3nrccd/return_fmtsprintf_vs_string/
This file contains hidden or 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 ( | |
"fmt" | |
"strconv" | |
"testing" | |
) | |
var ( | |
host string | |
port int | |
) | |
func init() { | |
host = "localhost" | |
port = 4444 | |
} | |
func HostStringSprintf() string { | |
return fmt.Sprintf("%s:%d", host, port) | |
} | |
func HostStringStrconv() string { | |
return host + ":" + strconv.Itoa(port) | |
} | |
func checkResult(t *testing.T, hostStr string) { | |
expected := "localhost:4444" | |
if hostStr != expected { | |
t.Fatal(hostStr, "!=", expected) | |
} | |
} | |
func TestSprintf(t *testing.T) { | |
hostStr := HostStringSprintf() | |
checkResult(t, hostStr) | |
} | |
func BenchmarkSprintf(b *testing.B) { | |
for n := 0; n < b.N; n++ { | |
HostStringSprintf() | |
} | |
} | |
func BenchmarkStrconv(b *testing.B) { | |
for n := 0; n < b.N; n++ { | |
HostStringStrconv() | |
} | |
} |
with my go1.6.2 darwin/amd64
BenchmarkSprintf-4 3000000 424 ns/op
BenchmarkStrconv-4 10000000 163 ns/op
go1.7.4 darwin/amd64
BenchmarkSprintf-4 5000000 257 ns/op
BenchmarkStrconv-4 20000000 101 ns/op
go version go1.8.3 linux/amd64
BenchmarkSprintf-2 5000000 248 ns/op
BenchmarkStrconv-2 20000000 106 ns/op
PASS
ok command-line-arguments 3.751s
go1.9 linux/amd64
BenchmarkSprintf-8 10000000 172 ns/op
BenchmarkStrconv-8 20000000 75.3 ns/op
go1.10 windows/amd64
goos: windows
goarch: amd64
pkg: bench
BenchmarkSprintf-8 10000000 169 ns/op
BenchmarkStrconv-8 20000000 72.3 ns/op
PASS
ok bench 3.459s
go version go1.11 linux/amd64
goos: linux
goarch: amd64
BenchmarkSprintf-4 10000000 179 ns/op
BenchmarkStrconv-4 20000000 75.0 ns/op
go version go1.12.1 windows/amd64
goos: windows
goarch: amd64
BenchmarkSprintf-16 10000000 193 ns/op
BenchmarkStrconv-16 20000000 60.4 ns/op
go version go1.12.3 darwin/amd64
goos: darwin
goarch: amd64
BenchmarkSprintf-12 10000000 151 ns/op
BenchmarkStrconv-12 30000000 45.4 ns/op
Added two more strategies:
package main
import (
"fmt"
"strconv"
"testing"
"unsafe"
)
var (
host string
port int
)
func init() {
host = "localhost"
port = 4444
}
func HostStringSprintf() string {
return fmt.Sprintf("%s:%d", host, port)
}
func HostStringStrconv() string {
return host + ":" + strconv.Itoa(port)
}
func HostStringStrconvBuffer() string {
buf := append([]byte(host), ':')
buf = strconv.AppendInt(buf, int64(port), 10)
return string(buf)
}
// This makes some really terrible assumptions about the way strings are handled in go,
// it is probably a better idea to use strings.Builder when actually doing unsafe things
// with strings a []byte.
func HostStringStrconvBufferUnsafe() string {
buf := append([]byte(host), ':')
buf = strconv.AppendInt(buf, int64(port), 10)
return *(*string)(unsafe.Pointer(&buf))
}
func checkResult(t *testing.T, hostStr string) {
expected := "localhost:4444"
if hostStr != expected {
t.Fatal(hostStr, "!=", expected)
}
}
func TestSprintf(t *testing.T) {
hostStr := HostStringSprintf()
checkResult(t, hostStr)
}
func TestHostStringStrConv(t *testing.T) {
hostStr := HostStringStrconv()
checkResult(t, hostStr)
}
func TestHostStringStrconvBuffer(t *testing.T) {
hostStr := HostStringStrconvBuffer()
checkResult(t, hostStr)
}
func TestHostStringStrconvBufferUnsafe(t *testing.T) {
hostStr := HostStringStrconvBufferUnsafe()
checkResult(t, hostStr)
}
func BenchmarkSprintf(b *testing.B) {
for n := 0; n < b.N; n++ {
HostStringSprintf()
}
}
func BenchmarkStrconv(b *testing.B) {
for n := 0; n < b.N; n++ {
HostStringStrconv()
}
}
func BenchmarkStrconvBuffer(b *testing.B) {
for n := 0; n < b.N; n++ {
HostStringStrconvBuffer()
}
}
func BenchmarkStrconvBufferUnsafe(b *testing.B) {
for n := 0; n < b.N; n++ {
HostStringStrconvBufferUnsafe()
}
}
go version go1.12.3 darwin/amd64
goos: darwin
goarch: amd64
BenchmarkSprintf-12 10000000 150 ns/op
BenchmarkStrconv-12 30000000 44.7 ns/op
BenchmarkStrconvBuffer-12 100000000 22.0 ns/op
BenchmarkStrconvBufferUnsafe-12 100000000 18.0 ns/op
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Results on single core server running Ubuntu 15.04 and Golang 1.4.1: