也许你已经猜到了,通道非常适用于对两个goroutine进行同步,当一个goroutine需要依赖另一个goroutine时,更是如此。事不宜迟,让我们马上来看看代码清单9-7所示的程序:这个程序沿用了上一节展示过的例子,唯一的不同在于,这次的程序使用了通道而不是等待组来对goroutine进行同步。
代码清单9-7 使用通道同步goroutine
package main
import (
"fmt"
"time"
)
func printNumbers2(w chan bool) {
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Microsecond)
fmt.Printf("%d ", i)
}
w <- true//把一个布尔值放入通道,以便解除主程序的阻塞状态
}
func printLetters2(w chan bool) {
for i := 'A'; i < 'A'+10; i++ {
time.Sleep(1 * time.Microsecond)
fmt.Printf("%c ", i)
}
w <- true//把一个布尔值放入通道,以便解除主程序的阻塞状态
}
func main() {
w1, w2 := make(chan bool), make(chan bool)
go printNumbers2(w1)
go printLetters2(w2)
//主程序将一直阻塞,直到通道里面出现可弹出的值为止
<-w1
<-w2
}
先来看看这个程序中的main
函数。它首先创建了w1
和w2
这两个bool
类型的通道,接着以goroutine方式运行了printNumbers2
函数和printLetters2
函数,并将两个通道分别传给了这两个函数。在启动两个goroutine
之后,main
函数将会尝试从通道w1
中移除一个值,但由于通道w1
当时并没有包含任何值,所以main
函数将会在此处阻塞。当printNumbers2
即将执行完毕,并将一个true
值放入通道w1
之后,main
函数的阻塞状态才会被解除,并继续尝试从第二个通道w2
中弹出一个值。跟之前一样,在printLetters2
执行完毕并将true
值放入通道w2
之前,main
函数将一直阻塞,直到它成功取得了w2
通道中的true
值之后,阻塞才会解除,然后main
函数才会顺利退出。
需要注意的是,因为我们只是想要在goroutine执行完毕之后解除对main
函数的阻塞,而不是真正地想要使用通道中存储的值,所以程序在从通道w1
和w2
里面取出值之后并没有使用这些值。
代码清单9-7展示的是一个非常简单的例子,这个例子中的程序使用通道只是为了对多个goroutine进行同步,但这些goroutine之间并没有通信。不过在接下来的一节,我们就会看到一个在多个goroutine之间传递消息的例子。