[go学习笔记]二11、共享内存并发机制

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)
}
复制代码

输出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

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()
}
复制代码

输出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 操做,就能很明显的看出,能够同时多个读,可是写的时候只能有一个写,而且不能读取;协程

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

方法string

  • Add()
  • Done()
  • Wait()

以前代码里边使用的是time.Sleep() 去等待其余协程执行完成,若是这个时间过大会形成多余的等待,若是太短,就会致使程序在其余协程尚未结束的状况下结束;it

WaitGroup.Add() // 有一个协程就 add 1

WaitGrop.Done() // 协程里边结束一个就完成一个

WaitGrop.Wait() // 最外层等待全部的协程,直到最后一个结束

相关文章
相关标签/搜索