更多学习笔记和示例代码请访问:github.com/wenjianzhan…
Lock
- Mutex
- RWLOCK
Mutex
func TestCounter(t *testing.T) {
counter := 0
for i := 0; i < 5000; i++ {
go func() {
counter++
}()
}
time.Sleep(1 * time.Second)
t.Logf("counter = %d", counter)
}
输出
=== RUN TestCounter
--- PASS: TestCounter (1.00s)
share_mem_test.go:17: counter = 4616
PASS
Process finished with exit code 0
结果表明,出现了多次并发最终结果 错误 ,因为 counter 在多协程中是共享的,所以,会出现抢占资源,导致 counter 最终结果出现差异;
使用 Mutex
func TestCounterSafe(t *testing.T) {
var mut sync.Mutex
counter := 0
for i := 0; i < 5000; i++ {
go func() {
defer func() {
mut.Unlock()
}()
mut.Lock()
counter++
}()
}
time.Sleep(1 * time.Second)
t.Logf("counter = %d", counter)
}
输出
=== RUN TestCounterSafe
--- PASS: TestCounterSafe (1.00s)
share_mem_test.go:33: counter = 5000
PASS
Process finished with exit code 0
这次结果和预期是一样的,是因为我们在协程中添加了 lock ,使用完成后给unlock掉;
RWLOCK
func read(i int, m *sync.RWMutex, wg *sync.WaitGroup) {
println(i, "read start")
m.RLock()
println(i, "reading")
time.Sleep(1 * time.Second)
m.RUnlock()
println(i, "read over")
wg.Done()
}
func write(i int, m *sync.RWMutex, wg *sync.WaitGroup) {
println(i, "write start")
m.Lock()
println(i, "writing")
time.Sleep(1 * time.Second)
m.Unlock()
println(i, "write over")
wg.Done()
}
func TestRWMutex(t *testing.T) {
var m = new(sync.RWMutex)
var wg = new(sync.WaitGroup)
wg.Add(3)
// 写的时候啥也不能干
go write(1, m, wg)
go read(2, m, wg)
go write(3, m, wg)
wg.Wait()
}
输出
=== RUN TestRWMutex
1 write start
1 writing
2 read start
3 write start
1 write over
2 reading
2 read over
3 writing
3 write over
--- PASS: TestRWMutex (3.01s)
PASS
Process finished with exit code 0
RWMutex 读锁是不是互斥的,但是写锁是互斥的,这样就提高了读的性能 可以尝试多加几个 Read 操作,就能很明显的看出,可以同时多个读,但是写的时候只能有一个写,并且不能读取;
WaitGroup
func TestCounterWaitGroup(t *testing.T) {
var mut sync.Mutex
var wg sync.WaitGroup
counter := 0
for i := 0; i < 5000; i++ {
wg.Add(1)
go func() {
defer func() {
mut.Unlock()
}()
mut.Lock()
counter++
wg.Done()
}()
}
wg.Wait()
t.Logf("counter = %d", counter)
}
输出
=== RUN TestCounterWaitGroup
--- PASS: TestCounterWaitGroup (0.00s)
share_mem_test.go:52: counter = 5000
PASS
Process finished with exit code 0
WaitGroup
方法
- Add()
- Done()
- Wait()
之前代码里边使用的是time.Sleep() 去等待其他协程执行完成,如果这个时间过大会造成多余的等待,如果过短,就会导致程序在其他协程还没有结束的情况下结束;
WaitGroup.Add() // 有一个协程就 add 1
WaitGrop.Done() // 协程里边结束一个就完成一个
WaitGrop.Wait() // 最外层等待所有的协程,直到最后一个结束
更多学习笔记和示例代码请访问:github.com/wenjianzhan…