虽然上次提过的sync控制并发很简单,但是他有一定的局限性,他也只能控制能过让所有的goroutine在程序结束时完成,并不能干涉各个goroutine,下面我们介绍一种更好的方式,就是利用通道;
首先先说用channel控制并发在程序结束之前完成:
func main(){
ch :=make(chan int) go func() { var sum int =0 for i :=0;i<10;i++{ sum +=i } ch <-sum }() fmt.Println(<-ch)
}
利用无缓冲通道,在通道没有接受到值之前,是不能执行fmt.Println(<-ch)语句的,这也就保证了,go func 可以执行完成
其次,还能利用channel,让两个goroutine之间传送数据:
func main(){
one := make(chan int) two :=make(chan int) go func() { fmt.Println("我是一号") one <- 100 }() go func() { fmt.Println("我是二号") v := <-one two <- v }() fmt.Println(<-two) }
结果:
D:\gowork\src\learn\12\1>go run chan.go
我是二号
我是一号
100
很明显在第二个goroutine中要接收到one中的数据才能往下进行,所以也就说明只有输出了上面的,下面的才会输出,从而达到了控制并发的效果
最后,还可以利用chan来控制一下持续进行的协程结束:
func main(){ stop :=make(chan bool) go func (){ for{ select{ case <- stop: fmt.Println("监控退出,停止了...") return default: fmt.Println("goroutin监控中...") time.Sleep(2*time.Second) } } }() time.Sleep(10*time.Second) fmt.Println("可以了,通知监控停止...") stop <- true time.Sleep(5*time.Second)
}
结果:
D:\gowork\src\learn\12\1>go run chan.go
goroutin监控中...
goroutin监控中...
goroutin监控中...
goroutin监控中...
goroutin监控中...
可以了,通知监控停止...
监控退出,停止了...
使用select+chan,当检测到chan中有值的时候,协程结束