32

Go并发编程小测验: 你能答对几道题?

 5 years ago
source link: https://colobu.com/2019/04/28/go-concurrency-quizzes/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

以下是10个Go并发编程的小测验,看看你能答对几道题?

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"
}
main --> A --> B --> C
main

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()
}

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()
}
  • A: 不能编译
  • B: 无输出,正常退出
  • C: 程序hang住
  • D: panic

4 双检查实现单例

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()
	}
}
  • A: 不能编译
  • B: 可以编译,正确实现了单例
  • C: 可以编译,有并发问题,f函数可能会被执行多次
  • D: 可以编译,但是程序运行会panic

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)
}
1, 1
1, 2

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)
}
  • A: 不能编译
  • B: 可以编译,运行时正常,内存稳定
  • C: 可以编译,运行时内存可能暴涨
  • D: 可以编译,运行时内存先暴涨,但是过一会会回收掉

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())
	}
}
#goroutines: 1
#goroutines: 2

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)
}

9 Map

package main

import (
	"fmt"
	"sync"
)

func main() {
	var m sync.Map
	m.LoadOrStore("a",1)
	m.Delete("a")

	fmt.Println(m.Len())
}

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)
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK