22.信道(channel)

原文:https://golangbot.com/channels/


欢迎来到Golang 系列教程的第 22 章。

在上一教程里,我们探讨了如何使用 Go 协程(Goroutine)来实现并发。我们接着在本教程里学习信道(Channel),学习如何通过信道来实现 Go 协程间的通信。

什么是信道?

信道可以想像成 Go 协程之间通信的管道。如同管道中的水会从一端流到另一端,通过使用信道,数据也可以从一端发送,在另一端接收。

信道的声明

所有信道都关联了一个类型。信道只能运输这种类型的数据,而运输其他类型的数据都是非法的。

chan T 表示 T 类型的信道。

信道的零值为 nil。信道的零值没有什么用,应该像对 map 和切片所做的那样,用 make 来定义信道。

下面编写代码,声明一个信道。

package mainimport "fmt"func main() {  var a chan intif a == nil {fmt.Println("channel a is nil, going to define it")a = make(chan int)fmt.Printf("Type of a is %T", a)}
}

在线运行程序

由于信道的零值为 nil,在第 6 行,信道 a 的值就是 nil。于是,程序执行了 if 语句内的语句,定义了信道 a。程序中 a 是一个 int 类型的信道。该程序会输出:

channel a is nil, going to define it  
Type of a is chan int  

简短声明通常也是一种定义信道的简洁有效的方法。

a := make(chan int) 

这一行代码同样定义了一个 int 类型的信道 a

通过信道进行发送和接收

如下所示,该语法通过信道发送和接收数据。

data := <- a // 读取信道 a  
a <- data // 写入信道 a  

信道旁的箭头方向指定了是发送数据还是接收数据。

在第一行,箭头对于 a 来说是向外指的,因此我们读取了信道 a 的值,并把该值存储到变量 data

在第二行,箭头指向了 a,因此我们在把数据写入信道 a

发送与接收默认是阻塞的

发送与接收默认是阻塞的。这是什么意思?当把数据发送到信道时,程序控制会在发送数据的语句处发生阻塞,直到有其它 Go 协程从信道读取到数据,才会解除阻塞。与此类似,当读取信道的数据时,如果没有其它的协程把数据写入到这个信道,那么读取过程就会一直阻塞着。

信道的这种特性能够帮助 Go 协程之间进行高效的通信,不需要用到其他编程语言常见的显式锁或条件变量。

信道的代码示例

理论已经够了:)。接下来写点代码,看看协程之间通过信道是怎么通信的吧。

我们其实可以重写上章学习Go协程 时写的程序,现在我们在这里用上信道。

首先引用前面教程里的程序。

package mainimport (  "fmt""time"
)func hello() {  fmt.Println("Hello world goroutine")
}
func main() {  go hello()time.Sleep(1 * time.Second)fmt.Println("main function")
}

在线运行程序

这是上一篇的代码。我们使用到了休眠,使 Go 主协程等待 hello 协程结束。如果你看不懂,建议你阅读上一教程Go 协程。

我们接下来使用信道来重写上面代码。

package mainimport (  "fmt"
)func hello(done chan bool) {  fmt.Println("Hello world goroutine")done &l


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部