High-quality programming and performance tuning practice

Introduction:

  • The premise of performance optimization is to meet quality factors such as correctness, reliability, simplicity and clarity
  • Performance optimization is a comprehensive evaluation, and sometimes time efficiency and space efficiency may be opposed

Performance Optimization Suggestions – Benchmark

The go language provides support for benchmark performance testing, how to use it has to be checked

slice

  • Slice pre-allocates memory, providing capacity information when initializing the slice with make() as much as possible

    data := make([]int,0)
    data := make([]int,0,10)
    
  • The underlying implementation of slices is a scalable linked list

  • Gotcha: Large memory not freed

    1. Creates a slice on top of an existing slice, without creating a new underlying array
    2. The original slice is larger, and the code creates a new small slice based on the original slice
    3. The original underlying array is referenced in memory and cannot be released
  • Copy can be used instead of re-slice

    func GetLastBySlice(origin []int) []int{
          
          
    	return origin[len(origin) - 2:]
    }
    
    // 下面这个节省的空间更多
    fun getLastByCopy(origin []int) []int{
          
          
    	result := make([]int,2)
    	copy(result,origin[len(origin) - 2:])
    	return result
    }
    

map

  • map pre-allocates memory
    • The operation of continuously adding new elements to the map will trigger the expansion of the map
    • Allocating space in advance can reduce memory copy and Rehash consumption
    • It is recommended to estimate the required space in advance according to the actual needs

strings.Buider for string processing

  • The performance of using + splicing is the worst, strings.Buider, bytes.Buffer are similar, strings. Buffer is faster
  • When the string is in go, it is an immutable type and occupies a fixed size
  • Using + will reallocate memory every time
  • Both strings.Buider and bytes.Buffer use []byte array at the bottom

Use empty structs to save memory

Use the atomic package

  • The realization of the lock is realized by the operating system, which belongs to the system call, and the call cost is very high

  • Atomic operations are implemented by hardware, which is more efficient than locks

  • sync.Mutex should be used to protect a piece of logic,. Not just for protecting a variable

  • For non-value operations, you can use atomic.Value, which can carry an interface{}

    type atomicCounter struct{
          
          
        i int32
    }
    func AtomicAddOne(c *atomicCounter){
          
          
        atomic.AddInt32(&c.i,1)
    }
    
    type mutexCounter struct{
          
          
        i int32
        m sync.Mutex
    }
    func MutexAddOne(c *mutexCounter){
          
          
        c.m.Lock()
        c.i++
        c.m.UnLock()
    }
    
    
    

summary:

  • Avoiding common performance pitfalls can guarantee the functionality of most programs
  • Ordinary application code, don't blindly pursue the performance of the program
  • The more advanced the performance optimization method, the more prone to problems
  • Improve program performance under the premise of meeting correct, reliable, concise and clear quality requirements

Guess you like

Origin blog.csdn.net/weixin_68798281/article/details/131997060