In this post I will describe how to concatenate string in the right / more performatic way.

The code will perform a long loop that appends some information in the current string

The Setup


package strings

import "bytes"

const maxIterations = 100000

func ConcatenateWrong() string {
	myVar := ""
	for i := 0; i < maxIterations; i++ {
		myVar = myVar + GenerateRandom()
	}
	return myVar
}

func ConcatenateRight() string {
	var buffer bytes.Buffer
	for i := 0; i < maxIterations; i++ {
		buffer.WriteString(GenerateRandom())
	}
	return buffer.String()
}

The test


package strings

import (
	"fmt"
	"testing"
	"time"
)

func TestConcatenate(t *testing.T) {
	start := time.Now()
	ConcatenateWrong()
	elapsed := time.Since(start)
	fmt.Printf("ConcatenateWrong - Elapsed time is %s\n", elapsed)
	//fmt.Println(wrong)

	start = time.Now()
	ConcatenateRight()
	elapsed = time.Since(start)
	fmt.Printf("ConcatenateRight - Elapsed time is %s\n", elapsed)
	//fmt.Println(right)
}


The Output:

/home/mussatto/dev/go-1.7/bin/go test -v github.com/mussatto/golab/strings -run ^TestConcatenate$
ConcatenateWrong - Elapsed time is 918.970641ms
ConcatenateRight - Elapsed time is 12.987911ms
ok  	github.com/mussatto/golab/strings	0.937s

As we can see, there is a perceptive difference of performace when using there two different approachs (~920ms vs ~13ms)

Analysis

When we concatenate using the plus “+” operation, it instantiates (creates) a new variable with the concatenated value.

As the string grows, it becomes a costly operation to create / alloc / instantiate the new variable and destroy the old one.

With buffer.WriteString, the old variable is not destroyed and only the passed value is appended. Without the need to create the performace is better.

The code

Github Link