Skip to content

Conversation

@zjumathcode
Copy link

Assistance Disclosure

strings.Builder has fewer memory allocations and better performance.
More info: golang/go#75190

@CLAassistant
Copy link

CLAassistant commented Nov 25, 2025

CLA assistant check
All committers have signed the CLA.

@vnxme
Copy link
Contributor

vnxme commented Nov 25, 2025

Interested to see any tests showing how much the performance gain is, if any, in ns per request or requests per second.

@zjumathcode
Copy link
Author

@vnxme I wrote a benchmark that shows the performance advantage of using strings.Builder, as follows:

package caddy_test

import (
	"fmt"
	"strings"
	"testing"
)

type Route struct {
	Group          string
	MatcherSetsRaw string
	HandlersRaw    []string
	Terminal       bool
}

func (r Route) StringOld() string {
	handlersRaw := "["
	for _, hr := range r.HandlersRaw {
		handlersRaw += " " + string(hr)
	}
	handlersRaw += "]"

	return fmt.Sprintf(`{Group:"%s" MatcherSetsRaw:%s HandlersRaw:%s Terminal:%t}`,
		r.Group, r.MatcherSetsRaw, handlersRaw, r.Terminal)
}

func (r Route) StringNew() string {
	var handlersRaw strings.Builder
	handlersRaw.WriteString("[")
	for _, hr := range r.HandlersRaw {
		handlersRaw.WriteString(" " + string(hr))
	}
	handlersRaw.WriteString("]")

	return fmt.Sprintf(`{Group:"%s" MatcherSetsRaw:%s HandlersRaw:%s Terminal:%t}`,
		r.Group, r.MatcherSetsRaw, handlersRaw.String(), r.Terminal)
}

func BenchmarkRouteString_Old(b *testing.B) {
	r := Route{
		Group:          "api",
		MatcherSetsRaw: "[matcher]",
		HandlersRaw:    []string{"foo", "bar", "baz", "qux", "quux"},
		Terminal:       true,
	}
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = r.StringOld()
	}
}

func BenchmarkRouteString_New(b *testing.B) {
	r := Route{
		Group:          "api",
		MatcherSetsRaw: "[matcher]",
		HandlersRaw:    []string{"foo", "bar", "baz", "qux", "quux"},
		Terminal:       true,
	}
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = r.StringNew()
	}
}
➜  benchmark go test -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: demo/stringsbuilder/benchmark
cpu: Apple M4
BenchmarkRouteString_Old-10      5239779               211.3 ns/op           248 B/op         10 allocs/op
BenchmarkRouteString_New-10      6258066               193.5 ns/op           200 B/op          7 allocs/op
PASS
ok      demo/stringsbuilder/benchmark 3.482s

@vnxme
Copy link
Contributor

vnxme commented Dec 5, 2025

@zjumathcode Thanks, so you have an 8% gain in ns/op, a 19% decrease in B/op and a 30% drop in allocs/op in your benchmark which is quite good. Does your PR cover all the places in the code where strings are concatenated?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants