Select basic usage

func generator() chan int {
   out := make(chan int)
   go func() {
      i := 0
      for {
         time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
         out <- i
         i++
      }

   }()
   return out
}

func main() {
   var c1, c2 = generator(), generator()
   for {
      select {
      case n := <-c1:
         fmt.Println("received from c1 ", n)
      case n := <-c2:
         fmt.Println("received from c2 ", n)
         //default:
         // fmt.Println("No value received")
      }
   }

}
Copy the code

If you look at the result of the execution, in fact, the select keyword is used to get the value from the case of the chan first, that’s all.

Of n Chan’s, choose the one that arrives first.

atomic

Most languages have the concept of atomic operations and locking. Go is no exception

Go also provides functions for native atomic operations. I’m not going to do it here, but it’s pretty much the same as Java

Let’s see how locks are used in the go language

Let’s mimic this atomic experiment

package main

import (
   "fmt"
   "time"
)

type atomicInt int

func (a *atomicInt) increase() {
   *a++
}

func (a *atomicInt) get() int{
  return int(*a)
}

func main() {
   var a atomicInt
   a.increase()
   go func() {
      a.increase()
   }()
   time.Sleep(time.Millisecond)
   fmt.Println(a.get())
}
Copy the code

Obviously there’s something wrong with this program. Because your increase and get functions are unlocked, they look like they can be executed concurrently. This, of course, can lead to incorrect final results at high concurrency

But actually when we run and look at this program it turns out to be 2 which is what we expected. Why is that? This is because the scenario is difficult to emulate in a single Goroutine, but evidence can be found with a few commands.

We can use go run-race to check the running process of the application

So you can see that you’ve given a warning that there’s a data race.

And I told you that lines 15 and 25 are read together and it’s not a problem to read together but to write together is a problem

Now use mutex to lock

package main

import (
   "fmt"
   "sync"
   "time"
)

type atomicInt struct {
   value int
   lock  sync.Mutex
}

func (a *atomicInt) increase() {
   a.lock.Lock()
   defer a.lock.Unlock()
   a.value++

}

func (a *atomicInt) get() int {
   a.lock.Lock()
   defer a.lock.Unlock()
   return a.value
}

func main() {
   var a atomicInt
   a.increase()
   go func() {
      a.increase()
   }()
   time.Sleep(time.Millisecond)
   fmt.Println(a.get())
}
Copy the code

Just take a second look