之前学习的Goroutine可以让我们便捷的进行并行编程,而通道则可以让我们方便的实现Goroutine之间的通信。
一个简单的通道使用示例:
package main
import ( "fmt" "time")func slowFunc(c chan string) { time.Sleep(time.Second * 2) c <- "slowFunc() finished"}func main() { c := make(chan string) go slowFunc(c) msg := <-c fmt.Println(msg)}
这个Go程序中,我们定义了一个传送消息类型为string的通道,我们还开启了一个Goroutine,主函数执行到msg := <-c时会阻塞,直到收到一条从通道c发来的消息为止。
通道还具有缓冲的功能,下面的程序我们使用了一个缓冲区大小为2的通道:
package main
import ( "fmt" "time")func receiver(c chan string) { for msg := range c { fmt.Println(msg) }}func main() { messages := make(chan string, 2) messages <- "hello" messages <- "world" close(messages) fmt.Println("Pushed two messages onto channel with no receivers") time.Sleep(time.Second * 1) receiver(messages)}
运行该程序可知,即使调用close()关闭了通道后,已发送的消息依然保留在通道的缓冲中,只是无法再向通道发送消息。在receiver()函数中我们接收了通道中的所有消息并打印。
在实际项目中,我们很可能需要使用一个通道不断地传送数据,借助for语句我们可以实现这一点:
package main
import ( "fmt" "time")func pinger(c chan string) { t := time.NewTicker(1 * time.Second) for { c <- "ping" <-t.C }}func main() { messages := make(chan string) go pinger(messages) for { msg := <-messages fmt.Println(msg) }}
此例为不断地通过通道发送和接收数据。
除此之外,还有select语句,它类似于switch语句,会执行最先收到消息的通道的case语句
package main
import ( "fmt" "time")func ping1(c chan string) { time.Sleep(time.Second * 1) c <- "ping on channel1"}func ping2(c chan string) { time.Sleep(time.Second * 2) c <- "ping on channel2"}func main() { channel1 := make(chan string) channel2 := make(chan string) go ping1(channel1) go ping2(channel2) select { case msg1 := <-channel1: fmt.Println("received", msg1) case msg2 := <-channel2: fmt.Println("received", msg2) }}
从此程序可知,接收到一条消息后,select语句将不再阻塞。
如果不想select语句无限的阻塞,可以专门使用一个通道来接收退出消息,称之为退出通道,如下:
package main
import ( "fmt" "time")func sender(c chan string) { for { c <- "I'm sending a message" time.Sleep(time.Second * 1) }}func stopFunc(c chan bool) { time.Sleep(time.Second * 2) fmt.Println("Time's up!") c <- true}func main() { messages := make(chan string) stop := make(chan bool) go sender(messages) go stopFunc(stop) for { select { case <- stop: return case msg:= <- messages: fmt.Println(msg) } }}