Val, That's a lot of speculation!
The original benchmark applies to the original question: prefix := verylongstring[:3] If we change the parameters of the benchmark then we expect to get different results. For example, read the Go gc compiler code. There's a stack/heap optimization for 32 bytes or less. cmd/gc: allocate buffers for non-escaped strings on stack commit e6fac08146df323eb95f46508bef937cdfb802fd https://go.googlesource.com/go/+/e6fac08146df323eb95f46508bef937cdfb802fd https://go-review.googlesource.com/c/go/+/3120 3 byte prefix: BenchmarkNil-4 10000000 173 ns/op 16 B/op 2 allocs/op BenchmarkLiteral-4 10000000 171 ns/op 16 B/op 2 allocs/op BenchmarkConvert-4 20000000 76.9 ns/op 3 B/op 1 allocs/op BenchmarkCopy-4 20000000 67.1 ns/op 3 B/op 1 allocs/op BenchmarkLoop-4 20000000 65.7 ns/op 3 B/op 1 allocs/op 32 byte prefix: BenchmarkNil-4 5000000 235 ns/op 64 B/op 2 allocs/op BenchmarkLiteral-4 10000000 232 ns/op 64 B/op 2 allocs/op BenchmarkConvert-4 10000000 129 ns/op 32 B/op 1 allocs/op BenchmarkCopy-4 10000000 118 ns/op 32 B/op 1 allocs/op BenchmarkLoop-4 10000000 183 ns/op 32 B/op 1 allocs/op 33 byte prefix: BenchmarkNil-4 5000000 295 ns/op 96 B/op 2 allocs/op BenchmarkLiteral-4 5000000 285 ns/op 96 B/op 2 allocs/op BenchmarkConvert-4 5000000 251 ns/op 96 B/op 2 allocs/op BenchmarkCopy-4 10000000 143 ns/op 48 B/op 1 allocs/op BenchmarkLoop-4 10000000 188 ns/op 48 B/op 1 allocs/op 256 byte prefix: BenchmarkNil-4 2000000 661 ns/op 512 B/op 2 allocs/op BenchmarkLiteral-4 2000000 665 ns/op 512 B/op 2 allocs/op BenchmarkConvert-4 2000000 659 ns/op 512 B/op 2 allocs/op BenchmarkCopy-4 5000000 369 ns/op 256 B/op 1 allocs/op BenchmarkLoop-4 2000000 883 ns/op 256 B/op 1 allocs/op $ go version go version devel +33484a6 Tue Aug 22 08:09:42 2017 +0000 linux/amd64 $ go test -run=! -bench=. -benchmem strslice_test.go goos: linux goarch: amd64 https://play.golang.org/p/tAYyecoQXY $ cat strslice_test.go package main import ( "strings" "testing" ) const pfxLen = 3 // 3, 32, 33, 256 var ( s = strings.Repeat("a very, very long string", 4096) prefix string ) func BenchmarkNil(b *testing.B) { for i := 0; i < b.N; i++ { prefix = string(append([]byte(nil), s[:pfxLen]...)) } } func BenchmarkLiteral(b *testing.B) { for i := 0; i < b.N; i++ { prefix = string(append([]byte{}, s[:pfxLen]...)) } } func BenchmarkConvert(b *testing.B) { for i := 0; i < b.N; i++ { prefix = string([]byte(s[:pfxLen])) } } func BenchmarkCopy(b *testing.B) { for i := 0; i < b.N; i++ { buffer := make([]byte, pfxLen) copy(buffer, s) prefix = string(buffer) } } func BenchmarkLoop(b *testing.B) { for i := 0; i < b.N; i++ { buffer := make([]byte, pfxLen) for i := 0; i < len(buffer); i++ { buffer[i] = s[i] } prefix = string(buffer) } } $ Peter On Tuesday, August 22, 2017 at 8:07:01 AM UTC-4, Val wrote: > > FWIW, append is most often a small performance penalty when the number of > elements is known ahead. > And for some reason, using built-in func copy, or an explicit loop, is > slightly faster on my workstation than BenchmarkConvert. > Also, "small benchmarks are hard" so I suspect the small allocations in > tight benchmark loops may not be representative of their real cost in a > real program. > > > func BenchmarkCopy(b *testing.B) { > for i := 0; i < b.N; i++ { > buffer := make([]byte, 3) > copy(buffer, s[:3]) > prefix = string(buffer) > } > } > > func BenchmarkLoop(b *testing.B) { > for i := 0; i < b.N; i++ { > buffer := make([]byte, 3) > for i := 0; i < 3; i++ { > buffer[i] = s[i] > } > prefix = string(buffer) > } > } > > > BenchmarkNil-4 30000000 61.9 ns/op 16 > B/op 2 allocs/op > BenchmarkLiteral-4 30000000 59.6 ns/op 16 > B/op 2 allocs/op > BenchmarkConvert-4 50000000 37.4 ns/op 3 > B/op 1 allocs/op > BenchmarkCopy-4 50000000 30.8 ns/op 3 > B/op 1 allocs/op > BenchmarkLoop-4 50000000 29.3 ns/op 3 > B/op 1 allocs/op > > Cheers > Val > > On Tuesday, August 22, 2017 at 1:01:36 PM UTC+2, peterGo wrote: >> >> A benchmark; >> >> https://play.golang.org/p/oUyeldDG5Q >> >> $ cat strslice_test.go >> package main >> >> import ( >> "strings" >> "testing" >> ) >> >> var ( >> s = strings.Repeat("a very, very long string", 4096) >> prefix string >> ) >> >> func BenchmarkNil(b *testing.B) { >> for i := 0; i < b.N; i++ { >> prefix = string(append([]byte(nil), s[:3]...)) >> } >> } >> >> func BenchmarkLiteral(b *testing.B) { >> for i := 0; i < b.N; i++ { >> prefix = string(append([]byte{}, s[:3]...)) >> } >> } >> >> func BenchmarkConvert(b *testing.B) { >> for i := 0; i < b.N; i++ { >> prefix = string([]byte(s[:3])) >> } >> } >> >> $ go test -run=! -bench=. -benchmem strslice_test.go >> goos: linux >> goarch: amd64 >> BenchmarkNil-4 10000000 174 ns/op 16 B/op >> 2 allocs/op >> BenchmarkLiteral-4 10000000 174 ns/op 16 B/op >> 2 allocs/op >> BenchmarkConvert-4 20000000 77.0 ns/op 3 B/op >> 1 allocs/op >> PASS >> ok command-line-arguments 5.512s >> $ >> >> Peter >> >> On Tuesday, August 22, 2017 at 12:15:44 AM UTC-4, Tamás Gulácsi wrote: >>> >>> prefix := string([]byte(verylongstring[:3])) >> >> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.