I have a tweak question. I had some repetitive pieces of code in my web-app requests where simple things like fmt.Sprintf("%d%d", 01293123, 234993923)
happens.
Now I did some benchmarks and tested a bytes writer, which was quite slow (~400 ns/op). The sprintf
itself was about 240 ns/op. Then I did strings joining:
var concatBuffStr []byte
func BenchmarkStringsJoin(b *testing.B) {
for n := 0; n < b.N; n++ {
concatBuffStr = []byte(strings.Join([]string{
strconv.Itoa(2),
strconv.Itoa(3),
}, " "))
}
}
152 ns/op
A big improvement already. But then I tried clunking 2 ints converted to bytes together
var concatBuffStr []byte
func BenchmarkConcatIntsAsBytes(b *testing.B) {
for n := 0; n < b.N; n++ {
aBuf := make([]byte, 8)
bBuf := make([]byte, 8)
binary.BigEndian.PutUint64(aBuf, uint64(2))
binary.BigEndian.PutUint64(bBuf, uint64(3))
concatBuffStr = append(aBuf, bBuf...)
}
}
57.8 ns/op
Amazing! But I could just avoid glueing them together and already reserve the full 16 bytes for 2 maxed out 64 bit uints spaces:
var concatBuffStr []byte
func BenchmarkCopyIntsAsBytes(b *testing.B) {
for n := 0; n < b.N; n++ {
concatBuffStr = make([]byte, 16)
bBuf := make([]byte, 8)
binary.BigEndian.PutUint64(concatBuffStr, uint64(123123))
binary.BigEndian.PutUint64(bBuf, uint64(3453455))
copy(concatBuffStr[8:], bBuf)
}
}
30.4 ns/op
By now we're 8 times faster than with the fmt.Sprintf()
method.
Was wondering if there is an even faster way than this. I want to avoid unsafe
tho.
I was also thinking of checking the max value of both 2 ints and if they are below the MAX of an uint32
or uint16
I could customize the logic. Benchmarking the uint16
downgrade by hand is around 23 ns/op
, but that's not realistic as in the web-request itself it would still need to check the size of the ints and do extra logic, which will likely result in more overhead than that 7 ns/op
gain.
Update
I managed to simplify it a little bit more:
var concatBuffStr []byte
func BenchmarkCopyIntsAsBytesShort(b *testing.B) {
for n := 0; n < b.N; n++ {
concatBuffStr = make([]byte, 16)
binary.BigEndian.PutUint64(concatBuffStr, uint64(123123))
binary.BigEndian.PutUint64(concatBuffStr[8:], uint64(3453455))
}
}
28.6 ns/op