目录
收集了一些Golang中同步的方式,做一下笔记,未完待续。。
1.channel
概述
Golang以如此明显的方式告诉我们:。
优点:channel的核心是数据流动,关注到并发问题中的数据流动,把流动的数据放到channel中,就能使用channel解决这个并发
问题,而且使用channel是线程安全的并且不会有数据冲突,比锁好用多了
缺点:不太适应同步太复杂的场景,比如多协程的同步等待问题,而且存在死锁问题 ,channel死锁问题:死锁问题链接
分类
channel类型:无缓冲和缓冲类型
channel有两种形式的,一种是无缓冲的,一个线程向这个channel发送了消息后,会阻塞当前的这个线程,知道其他线程去接收这个channel的消息。无缓冲的形式如下:
intChan := make(chan int)
带缓冲的channel,是可以指定缓冲的消息数量,当消息数量小于指定值时,不会出现阻塞,超过之后才会阻塞,需要等待其他线程去接收channel处理,带缓冲的形式如下:
//3为缓冲数量
intChan := make(chan int, 3)
举例
type Person struct {
Name string
Age uint8
Address Addr
}
type Addr struct {
city string
district string
}
/*
测试channel传输复杂的Struct数据
*/
func testTranslateStruct() {
personChan := make(chan Person, 1)
person := Person{"xiaoming", 10, Addr{"shenzhen", "longgang"}}
personChan <- person
person.Address = Addr{"guangzhou", "huadu"}
fmt.Printf("src person : %+v \n", person)
newPerson := <-personChan
fmt.Printf("new person : %+v \n", newPerson)
}
在实际应用过程中,等待channel 结束信号的过程可能不是无期限的,一般会伴随一个timer,超时时间如下面所示:
/*
检查channel读写超时,并做超时的处理
*/
func testTimeout() {
g := make(chan int)
quit := make(chan bool)
go func() {
for {
select {
case v := <-g:
fmt.Println(v)
case <-time.After(time.Second * time.Duration(3)):
quit <- true
fmt.Println("超时,通知主线程退出")
return
}
}
}()
for i := 0; i < 3; i++ {
g <- i
}
<-quit
fmt.Println("收到退出通知,主线程退出")
}
2.Sync.Mutex
3. Sync.waitGroup
Channel在某些同步场景下,使用略显复杂,不管是使用多个channel还是使用channel数组,如下:
func coordinateWithChan() {
sign := make(chan struct{}, 2)
num := int32(0)
fmt.Printf("The number: %d [with chan struct{}]\n", num)
max := int32(10)
go addNum(&num, 1,