Go 并发(二)

Go Mutex

经过Mutex和信道处理竞态条件。并发

临界区

当程序并发运行时,多个协程不该该同时访问那些修改共享资源的代码,这些修改共享资源的代码称为临界区。线程

Go中经过Mutex能够避免同时访问临界区,从而避免了竞态条件。code

Mutex

Mutex提供了一种锁机制,能够确保某个时刻只有一个协程在临界区运行,防止出现竞态条件。server

Mutex中定义了两个方法:Lock和Unlock。 Lock和Unlock之间的代码只能由一个协程执行,避免了竞态条件。协程

mutex.Lock()
x = x+1
mutex.Unlock()

经过Mutex避免竞态

Var x = 0
func increment(wg *sync.WaitGroup, m *sync.Mutex){
	m.Lock()
	x = x+1
	m.Unlock()
	wm.Done()
}

func main(){
	var w sync.WaitGroup
	var m sync.Mutex
	for I := 0; I < 1000; I++{
		w.Add(1)
		go increment(&w, &m)
	}
	w.Wait()
}

Go select

Select用于在多个发送/接收信道中进行选择,select语句会一直阻塞,直到发送/接收操做准备就绪。资源

若是有多个信道操做准备就绪,select会随机选择其中之一执行。rem

output1 := make(chan string)
output2 := make(chan string)

go server1(output1)
go server2(output2)

select{
	case s1 := <-output1:
		print
	case s2:= <-output2:
		print
}

select 会一直阻塞,除非某个case准备就绪。string

经过select中的case能够避免信道死锁,由于case表明有没有就绪。it

若是一个select没有任何case,会一直阻塞,致使死锁。select

Go WaitGroup

WaitGroup

WaitGroup用于等待一批Go协程执行结束,程序控制会一直阻塞,直到这些协程所有执行完毕才会终止。

func process(I int, wg *sync.WaitGroup){
	// do something
	wg.Done() // 让计数器减一
}

func main(){
	no := 3
	var wg sync.WaitGroup
	for I := 0; I < no; I++{
		wg.Add(1) // 循环3次计数器变成3
		go process(I, &wg) // 传递地址很重要,若是不传递地址,每一个协程都会获得一个WaitGroup的值拷贝,这样就不能经过一个计数器控制协做了
	}
	wg.Wait() // 等待主线程变成0
}

WaitGroup使用计数器来工做。调用WaitGroup的Add并传递一个int,作累加,减小可调用Done方法。 Wait()方法会阻塞调用WaitGroup的协程,直到计数器为0后才会中止阻塞。

相关文章
相关标签/搜索