golang中并发sync和channel
浏览量:445
golang中实现并发非常简单,只需在需要并发的函数前面添加关键字"go",但是如何处理go并发机制中不同goroutine之间的同步与通信,
golang 中提供了sync包和channel机制来解决这一问题.
WaitGroup总共有三个方法:Add(delta int), Done(), Wait()。
Add:添加或者减少等待goroutine的数量
Done:相当于Add(-1)
Wait:执行阻塞,直到所有的WaitGroup数量变成0
例子:
package main import ( "fmt" "sync" ) var waitgroup sync.WaitGroup func Afuntion(shownum int) { fmt.Println(shownum) waitgroup.Done()//任务完成,将任务队列的任务数量-1 其实 done 就是add(+1) } func main(){ for i:=1;i<10 ;i++ { waitgroup.Add(1)//每创建一个go routine就把队列中的任务数量+1 go Afuntion(i) } waitgroup.Wait()//Wait这里会发生堵塞,直到队列所有的任务结束,结束堵塞 }
答案:不一样的数据读出来
使用场景:
程序中需要并发,需要创建多个goroutine,并且一定要等这些并发全部完成后才继续接下来的程序执行.WaitGroup的特点是Wait()可以用来阻塞直到队列中的所有任务都完成时才解除阻塞,
而不需要sleep一个固定的时间来等待.但是其缺点是无法指定固定的goroutine数目.
Channel机制:
对于channel操作只有4种方式:
创建channel(通过make()函数实现,包括无缓存channel和有缓存channel);
向channel中添加数据(channel<-data);
从channel中读取数据(data<-channel);
关闭channel(通过close()函数实现,关闭之后无法再向channel中存数据,但是可以继续从channel中读取数据)
channel分为有缓冲channel和无缓冲channel,两种channel的创建方法如下:
var ch = make(chan int) //无缓冲channel,等同于make(chan int ,0)
var ch = make(chan int,10) //有缓冲channel,缓冲大小是5
无缓存channel:
package main import ( "fmt" ) func Afun(ch chan int) { fmt.Println("finish") <-ch } func main(){ ch := make(chan int) go Afun(ch) ch <- 1 } //输出结果:finish
package main import ( "fmt" ) func Afun(ch chan int) { fmt.Println("finish") <-ch } func main(){ ch := make(chan int) ch <- 1 go Afun(ch) } //输出结果: 没有结果
代码分析:首先创建一个无缓冲的channel, 然后在主协程里面向channel ch 中通过ch<-1命令写入数据,则此时主协程阻塞,就无法执行下面的go Afuntions(ch),
自然也就无法解除主协程的阻塞状态,则系统死锁
close():
close主要用来关闭channel通道其用法为close(channel),并且实在生产者的地方关闭channel,而不是在消费者的地方关闭.并且
关闭channel后,便不可再想channel中继续存入数据,但是可以继续从channel中读取数据.例子如下:
package main import "fmt" func main(){ var ch = make(chan int, 20) for i:=0; i < 10 ;i++ { ch <- i } close(ch) for j:= range ch { fmt.Println(j); } }
答案:
//输出0 1 2 3 4 5 6 7 8 9
channel阻塞超时处理:
goroutine有时候会进入阻塞情况,那么如何避免由于channel阻塞导致整个程序阻塞的发生那?解决方案:通过select设置超时处理,
具体程序如下:
package main import ( "fmt" "time" ) func main() { c := make(chan int) o := make(chan bool) go func() { for { select { case i:= <- c: fmt.Println(i) case <-time.After(time.Duration(3)*time.Second): fmt.Println("jieshu") o<-true break } } }() <-o }
golang 并发总结:
并发两种方式:sync.WaitGroup,该方法最大优点是Wait()可以阻塞到队列中的所有任务都执行完才解除阻塞,但是它的缺点是不能够指定并发协程数量.
channel优点:能够利用带缓存的channel指定并发协程goroutine,比较灵活.但是它的缺点是如果使用不当容易造成死锁;并且他还需要自己判定并发goroutine是否执行完.
但是相对而言,channel更加灵活,使用更加方便,同时通过超时处理机制可以很好的避免channel造成的程序死锁,因此利用channel实现程序并发,更加方便,更加易用.
神回复
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。