Go语言学习笔记-通道
之前学习的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)
}
}
}