Variadic Append Performance

November 4, 2018

I wanted to write a quick post on the performance that a variadic append has in Go. I was chatting with a co-worker last week and we were both under the impression that if you used a variadic append it was the same performance as if you iterated and appended one value at a time.

var slice []int
slice = append(slice, otherSlice...)

vs

var slice []int
for _, i := range otherSlice {
  slice = append(slice, i)
}

I ran some benchmarks locally and kept seeing that variadic was indeed faster than if you were iterating which was really nice to see! In order to confirm my findings I was able to find https://github.com/jeromefroe/golang_benchmarks#append and ran those benchmarks confirming that variadic is faster. The author there voices a suspicion that the reason variadic is faster is due to a compiler optimization of using a single memcpy call when using the variadic approach.

The benchmarks in that repo for append look something like this:

package main

import "testing"

const (
	sliceSize = 1024
)

var (
	srcSlice = make([]int64, sliceSize)
	dstSlice = make([]int64, 0, sliceSize)
)

func BenchmarkAppendLoop(b *testing.B) {
	for i := 0; i < b.N; i++ {
		dstSlice = dstSlice[:0]
		for j := 0; j < len(srcSlice); j++ {
			dstSlice = append(dstSlice, srcSlice[j])
		}
	}
}

func BenchmarkAppendVariadic(b *testing.B) {
	for i := 0; i < b.N; i++ {
		dstSlice = dstSlice[:0]
		dstSlice = append(dstSlice, srcSlice...)
	}
}
goos: darwin
goarch: amd64
pkg: github.com/josebalius/sliceperf
BenchmarkAppendLoop-4       	 1000000	      1422 ns/op
BenchmarkAppendVariadic-4   	20000000	        75.5 ns/op
PASS
ok  	github.com/josebalius/sliceperf	3.036s