Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which optimisations does the Go 1.6 compiler apply when converting between []byte and string or vice versa?

I know that converting from a []byte to a string, or vice versa, results in a copy of the underlying array being made. This makes sense to me, from the point of view of strings being immutable.

Then I read here that two optimisations get made by the compiler in specific cases:

"The first optimization avoids extra allocations when []byte keys are used to lookup entries in map[string] collections: m[string(key)]."

This makes sense because the conversion is only scoped to the square brackets, so no risk of mutating the string there.

"The second optimization avoids extra allocations in for range clauses where strings are converted to []byte: for i,v := range []byte(str) {...}."

This makes sense because once again - no way of mutating the string here.

Also mentioned is further optimisations on the todo list (not sure which todo list is being referred to), so my question is:

Does any other such (further) optimisations exist in Go 1.6 and if so, what are they?

like image 567
yakutori Avatar asked Feb 07 '23 13:02

yakutori


1 Answers

[]byte to string

For []byte to string conversion, the compiler generates a call to the internal runtime.slicebytetostringtmp function (link to source) when it can prove

that the string form will be discarded before the calling goroutine could possibly modify the original slice or synchronize with another goroutine.

runtime.slicebytetostringtmp returns a string referring to the actual []byte bytes, so it does not allocate. The comment in the function says

// First such case is a m[string(k)] lookup where
// m is a string-keyed map and k is a []byte.
// Second such case is "<"+string(b)+">" concatenation where b is []byte.
// Third such case is string(b)=="foo" comparison where b is []byte.

In short, for a b []byte:

  • map lookup m[string(b)] does not allocate
  • "<"+string(b)+"> concatenation does not allocate
  • string(b)=="foo" comparison does not allocate

The second optimization was implemented on 22 Jan 2015, and it is in go1.6

The third optimization was implemented on 27 Jan 2015, and it is in go1.6

So, for example, in the following:

var bs []byte = []byte{104, 97, 108, 108, 111}

func main() {
    x := string(bs) == "hello"
    println(x)
}

the comparison does not cause allocations in go1.6.

String to []byte

Similarly, the runtime.stringtoslicebytetmp function (link to source) says:

// Return a slice referring to the actual string bytes.
// This is only for use by internal compiler optimizations
// that know that the slice won't be mutated.
// The only such case today is:
// for i, c := range []byte(str)

so i, c := range []byte(str) does not allocate, but you already knew that.

like image 133
Haile Avatar answered Feb 11 '23 21:02

Haile