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)
}
複製代碼
輸出shell
=== 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)
}
複製代碼
輸出ui
=== RUN TestCounterSafe
--- PASS: TestCounterSafe (1.00s)
share_mem_test.go:33: counter = 5000
PASS
Process finished with exit code 0
複製代碼
此次結果和預期是同樣的,是由於咱們在協程中添加了 lock ,使用完成後給unlock掉;spa
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()
}
複製代碼
輸出code
=== 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 操做,就能很明顯的看出,能夠同時多個讀,可是寫的時候只能有一個寫,而且不能讀取;協程
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
複製代碼
方法string
以前代碼裏邊使用的是time.Sleep() 去等待其餘協程執行完成,若是這個時間過大會形成多餘的等待,若是太短,就會致使程序在其餘協程尚未結束的狀況下結束;it
WaitGroup.Add() // 有一個協程就 add 1
WaitGrop.Done() // 協程裏邊結束一個就完成一個
WaitGrop.Wait() // 最外層等待全部的協程,直到最後一個結束