Written before performance optimization - understand some time-consuming concepts

Continue to create, accelerate growth! This is the first day of my participation in the "Nuggets Daily New Plan · June Update Challenge", click to view the details of the event

I'm not sure if you've seen this form

Haven't seen it, consider collecting it

operate Delay
execute an instruction 1 ns
L1 cache query 0.5 ns
Branch mispredict 3 ns
L2 cache query 4 ns
Mutex lock/unlock 17 ns
Send 2KB over a 1Gbps network 44 ns
main memory access 100 ns
Zippy compresses 1KB 2,000 ns
Read 1 MB sequentially from memory 3,000 ns
SSD random read 16,000 ns
Read 1 MB sequentially from SSD 49,000 ns
Round trip to the same data center 500,000 ns
Read 1 MB sequentially from disk 825,000 ns
disk addressing 2,000,000 ns (2 ms)
Packets sent from the US to Europe 150,000,000 ns(150 ms)

But sometimes just knowing these concepts is not enough

Since many times our choice is not between network transmission, memory, and hard disk, we certainly know that memory is greater than hard disk. This article is mainly to discuss the time-consuming of channels , atomic operations , and locks in the go language. First, we need to define the time-consuming. We define two coroutines to consume resources, and record the time-consuming after consuming 10,000 resources.

The test code is as follows:

// 通道
func Bgo(ch chan int, cnt chan int) {
   for {
      select {
      case a := <-ch:
         ch <- a + 1
         if a >= 10000 {
            cnt <- a + 1
            return
         }
      case <-time.After(1 * time.Second):
         cnt <- 7777
         return
      }
   }
}
// 原子操作
func Cgo(count *int64) {
   for {
      atomic.AddInt64(count, 1)
      if *count > 10000 {
         return
      }
   }
}
// 锁
func Dgo(count *int64) {
   defer lock.Unlock()
   for {
      lock.Lock()
      *count = *count + 1

      if *count > 10000 {
         return
      }
      lock.Unlock()
   }
}
复制代码

Recording time:

start = time.Now().UnixMicro()

ch <- 1
go Bgo(ch, cnt)
go Bgo(ch, cnt)
fmt.Println(<-cnt)
fmt.Println(time.Now().UnixMicro() - start)

// 两个协程原子操作
start = time.Now().UnixMicro()
var count int64 = 1
go Cgo(&count)
Cgo(&count)
fmt.Println(time.Now().UnixMicro() - start + count - 10001)
fmt.Println(count)

// 两个协程Mutex
start = time.Now().UnixNano()
var count1 int64 = 1
go Dgo(&count1)
Dgo(&count1)
fmt.Println(time.Now().UnixNano() - start + count1 - 10001)
fmt.Println(count1)
复制代码

in conclusion

From the conclusion, the time-consuming of the channel is the highest, the atomic operation is in the microsecond level, and the lock fluctuation is relatively large, and sometimes the nanosecond level cannot be counted.

This is also one of the reasons for this article. In my impression, the lock itself should not take so little time. Hope you guys can correct me.

Guess you like

Origin juejin.im/post/7101686337111228452