What is the point of setting the cutoff capacity?

In Golang, we can use the built-in make() function to create a slice with a given initial length and capacity.

Consider the following lines: the length of the slice is 1, and its capacity is 3:

 func main() { var slice = make([]int, 1, 3) slice[0] = 1 slice = append(slice, 6, 0, 2, 4, 3, 1) fmt.Println(slice) } 

I was surprised to see that this program prints:

[1 6 0 2 4 3 1]

This made me wonder: what's the point of initially defining the slice capacity if append() can just skip it? Is there a performance gain for installing a sufficiently large capacity?

+12
source share
2 answers

A slice is actually just a trendy way to manage a basic array. It automatically tracks the size and redistributes the new space as needed.

When added to a slice, the runtime doubles its capacity each time it exceeds its current capacity. He must copy all the elements to do this. If you know how big it will be before you start, you can avoid several copy and allocate operations by grabbing it all in advance.

When you make provide slice capacity, you set the initial capacity , not any limit .

Check out this slicer blog post for some interesting internal details about slicing.

+17
source

slice is a wonderful abstraction of a simple array . You get all sorts of nice features, but at the core is array . (I explain the following in reverse order for a reason). Therefore, if / when you specify capacity from 3 , an array of length 3 is allocated in the depth of memory in memory, which you can use before append without the need to reallocate memory. This attribute is optional on the make , but note that slice will always have capacity , regardless of whether you select it. If you specify length (which also always exists), slice will be indexable to that length. The rest of capacity is hidden behind the scenes, so it doesn't need to allocate a whole new array when using append .

Here is an example to better explain the mechanics.

s := make([]int, 1, 3)

The base array will be assigned 3 int values ​​of zero (i.e. 0 ):

[0,0,0]

However, length set to 1 , so the slice itself will print only [0] , and if you try to index the second or third value, it will be panic , since the slice mechanics do not. allow it. If you s = append(s, 1) to it, you will find that it was really created to contain zero values ​​up to length , and you will get [0,1] . At this point, you can append again before the entire base array is full, and another append will make it select a new one and copy all the values ​​with double capacity. This is actually a rather expensive operation.

So the short answer to your question is that pre-allocation of capacity can be used to significantly increase the efficiency of your code. Especially if slice will either be very large or contain complex structs (or both), since the zero value for the struct actually the zero value for each of its fields . This is not because it would avoid highlighting these values, as in any case, but because the append would have to redistribute a new array full of these null values ​​each time it would need to resize the underlying array.

A short example of a playground: https://play.golang.org/p/LGAYVlw-jr

+11
source

Source: https://habr.com/ru/post/1270405/


All Articles