This is the first day of my participation in the August Text Challenge.More challenges in August

preview

  • useappendrightsliceWhat’s wrong with appending? ifsliceToo long?
  • usemapWhat if I need to iterate sequentially?
  • If you just needchanTo control switches or trigger events, which type is more memory efficient?
  • What’s the difference between “for” and “range”?

Optimization Suggestions

1. Try to create a fixed lengthsliceTo avoid being reslice multiple times

If the required data length is known, make creates a capacity to avoid resliced to the new element **.

This is because when append is used to append slices, the slice capacity is reslice 2x each time if it is smaller than 1024, and the slice capacity is reslice 1.25x each time if it is larger than 1024.

Here is an example of slice’s reslice process capacity variation length to see how reslice increases capacity by default.

s := make([]int.0)
m := make(map[int]struct{}, 0)
for i := 0; i < 2000; i++ {
  m[cap(s)] = struct{}{}
  s = append(s, i)
}
for k := range m {
  fmt.Println("cap", k)
}
Copy the code

The output cap is sorted as follows: 0,1,2,4,8,16,32,64,128,256,512,1024,1280,1696,2304

This number of reslice copies the data to a new slice each time, which is a waste of time, space and time. It is better to specify the length directly when the slice length is known. Change the above example to the following

// make(type, length, capacity) to specify the capacity
s := make([]int.0.2000)
Copy the code

Then the output cap here is only 20000, without reslice, which is faster.

2. Use chan struct{} as a trigger without sending data.

Chan struct{} is recommended for chan that does not normally send data. This is the most memory efficient, with little extra memory wasted.

Empty struct{} does not take up memory space? Take a look at the following output:

fmt.Println(unsafe.Sizeof(struct{} {}))// Output: 0
fmt.Println(unsafe.Sizeof(true)) // Output: 1
Copy the code

Empty struct{} does take up no memory, so empty structures are widely used for placeholder purposes.

3. Use less range and more for subscripts for traversal. Range will have a copy

Range traversal can be written in three ways: subscript only, value only, and subscript and value at the same time.

// First, just iterate over the subscript
for index := range intSlice {
  fmt.Println(intSlice[index])
}
// The second way is to traverse only the values and have a copy of the data
for _, value := range intSlice {
  fmt.Println(value)
}
// The third way is to iterate over both the index and the value, and have a copy of the data
for index, value := range intSlice {
  fmt.Println(index, value)
}

// for traverses the index without extra overhead
for index := 0; index < len(intSlice) {
  fmt.Println(intSlice[index])
}
Copy the code

But! Range traverses values with a copy of the data, which is an additional overhead. This will lead to performance problems, so in the traversal process as little as possible lazy, write a few more subscript expressions to save more resources and save time.

But again! If you just iterate over subscripts, there is little difference between for and range. Or if the data itself is a pointer type, range is fine, because copies of range refer directly to the pointer with no overhead.

Use skills

1. What if the map needs to be traversed sequentially? Sorting key

When using a map, you may encounter sequential traversal. Usually, it is simple to save a separate slice of the key, sort the slice of the key, and traverse the slice to obtain the value of the map.

Is there an easier way to do this? At present, there is no good solution to map sequence output, after all, map implementation is like this, can only rely on external factors to interfere with map output order. If there is a better solution, welcome to discuss in the comments section.

review

  • Slice creation specifies a capacity to avoid being reslice multiple times
  • **struct{}** does not occupy memory, suitable for chan struct{} as trigger channel
  • Range copies the data. Avoid this
  • Sequentially traversing a map requires extra overhead to store and sort a map’s keys