Here are 10 Go concurrent programming quizzes to see how many questions you can answer correctly.
1 Mutex
package main
import (
"fmt"
"sync"
)
var mu sync.Mutex
var chain string
func main() {
chain = "main"
A()
fmt.Println(chain)
}
func A() {
mu.Lock()
defer mu.Lock()
chain = chain + " --> A"
B()
}
func B() {
chain = chain + " --> B"
C()
}
func C() {
mu.Lock()
defer mu.Lock()
chain = chain + " --> C"
}Copy the code
- A: Can’t compile
- B: the output
main --> A --> B --> C
- C: output
main
- D: panic
2 RWMutex
package main
import (
"fmt"
"sync"
"time"
)
var mu sync.RWMutex
var count int
func main() {
go A()
time.Sleep(2 * time.Second)
mu.Lock()
defer mu.Unlock()
count++
fmt.Println(count)
}
func A() {
mu.RLock()
defer mu.RUnlock()
B()
}
func B() {
time.Sleep(5 * time.Second)
C()
}
func C() {
mu.RLock()
defer mu.RUnlock()
}Copy the code
- A: Can’t compile
- B: the output
1
- C: Program hang
- D: panic
3 Waitgroup
package main
import (
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
time.Sleep(time.Millisecond)
wg.Done()
wg.Add(1)
}()
wg.Wait()
}Copy the code
- A: Can’t compile
- B: No output, exit normally
- C: Program hang
- D: panic
4 Double check implements a singleton
package doublecheck
import (
"sync"
)
type Once struct {
m sync.Mutex
done uint32
}
func (o *Once) Do(f func()) {
if o.done == 1 {
return
}
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
o.done = 1
f()
}
}Copy the code
- A: Can’t compile
- B: It can compile and implement singletons correctly
- C: It can compile, there are concurrency issues, and the f function may be executed multiple times
- D: It can compile, but the program will panic when running
5 Mutex
package main import ( "fmt" "sync" ) type MyMutex struct { count int sync.Mutex } func main() { var mu MyMutex mu.Lock() var mu2 = mu mu.count++ mu.Unlock() mu2.Lock() mu2.count++ mu2.Unlock() fmt.Println(mu.count, mu2.count) }Copy the code
- A: Can’t compile
- B: the output
1, 1
- C: output
1, 2
- D: panic
6 Pool
package main import ( "bytes" "fmt" "runtime" "sync" "time" ) var pool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }} func main() { go func() { for { processRequest(1 << 28) // 256MiB } }() for i := 0; i < 1000; i++ { go func() { for { processRequest(1 << 10) // 1KiB } }() } var stats runtime.MemStats for i := 0; ; i++ { runtime.ReadMemStats(&stats) fmt.Printf("Cycle %d: %dB\n", i, stats.Alloc) time.Sleep(time.Second) runtime.GC() } } func processRequest(size int) { b := pool.Get().(*bytes.Buffer) time.Sleep(500 * time.Millisecond) b.Grow(size) pool.Put(b) time.Sleep(1 * time.Millisecond) }Copy the code
- A: Can’t compile
- B: It can compile and run normally with stable memory
- C: It can compile and memory may explode at runtime
- D: It can be compiled, memory is inflated at runtime, but it will be reclaimed later
7 channel
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var ch chan int
go func() {
ch = make(chan int, 1)
ch <- 1
}()
go func(ch chan int) {
time.Sleep(time.Second)
<-ch
}(ch)
c := time.Tick(1 * time.Second)
for range c {
fmt.Printf("#goroutines: %d\n", runtime.NumGoroutine())
}
}Copy the code
- A: Can’t compile
- B: Always output after a period of time
#goroutines: 1
- C: Always output after a period of time
#goroutines: 2
- D: panic
8 channel
package main
import "fmt"
func main() {
var ch chan int
var count int
go func() {
ch <- 1
}()
go func() {
count++
close(ch)
}()
<-ch
fmt.Println(count)
}Copy the code
- A: Can’t compile
- B: the output
1
- C: output
0
- D: panic
9 Map
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
m.LoadOrStore("a", 1)
m.Delete("a")
fmt.Println(m.Len())
}Copy the code
- A: Can’t compile
- B: the output
1
- C: output
0
- D: panic
10 happens before
package main
var c = make(chan int)
var a int
func f() {
a = 1
<-c
}
func main() {
go f()
c <- 0
print(a)
}Copy the code
- A: Can’t compile
- B: the output
1
- C: output
0
- D: panic