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