这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
我们接下来开始对golang中另外一个比较重要的东西”通道”进行学习。
通道可以被认为是Goroutines通信的管道。类似于管道中的水从一端到另一端的流动,数据可以从一端发送到另一端,通过通道接收。
在前面讲Go语言的并发时候,我们就说过,当多个Goroutine想实现共享数据的时候,虽然也提供了传统的同步机制,但是Go语言强烈建议的是使用Channel通道来实现Goroutines之间的通信。
“不要通过共享内存来通信,而应该通过通信来共享内存” 这是一句风靡golang社区的经典语
Go语言中,要传递某个数据给另一个goroutine(协程),可以把这个数据封装成一个对象,然后把这个对象的指针传入某个channel中,另外一个goroutine从这个channel中读出这个指针,并处理其指向的内存对象。Go从语言层面保证同一个时间只有一个goroutine能够访问channel里面的数据,为开发者提供了一种优雅简单的工具,所以Go的做法就是使用channel来通信,通过通信来传递内存数据,使得内存数据在不同的goroutine中传递,而不是使用共享内存来通信。
通道的概念
通道是什么,通道就是goroutine之间的通道。它可以让goroutine之间相互通信。
每个通道都有与其相关的类型。该类型是通道允许传输的数据类型。(通道的零值为nil。nil通道没有任何用处,因此通道必须使用类似于map和切片的方法来定义。)
通道的声明
声明一个通道和定义一个变量的语法一样:
//声明通道
var 通道名 chan 数据类型
//创建通道:如果通道为nil(就是不存在),就需要先创建通道
通道名 = make(chan 数据类型)
复制代码
示例代码:
package main
import "fmt"
func main() {
var a chan int
if a == nil {
fmt.Println("channel 是 nil 的, 不能使用,需要先创建通道。。")
a = make(chan int)
fmt.Printf("数据类型是: %T", a)
}
}
复制代码
运行结果:
channel 是 nil 的, 不能使用,需要先创建通道。。
数据类型是: chan int
复制代码
也可以简短的声明:
a := make(chan int)
复制代码
channel的数据类型
channel是引用类型的数据,在作为参数传递的时候,传递的是内存地址。
示例代码:
package main
import (
"fmt"
)
func main() {
ch1 := make(chan int)
fmt.Printf("%T,%p\n",ch1,ch1)
test1(ch1)
}
func test1(ch chan int){
fmt.Printf("%T,%p\n",ch,ch)
}
复制代码
运行结果:
我们能够看到,ch和ch1的地址是一样的,说明它们是同一个通道。
通道的注意点
Channel通道在使用的时候,有以下几个注意点:
- 1.用于goroutine,传递消息的。
- 2.通道,每个都有相关联的数据类型, nil chan,不能使用,类似于nil map,不能直接存储键值对
- 3.使用通道传递数据:<- chan <- data,发送数据到通道。向通道中写数据 data <- chan,从通道中获取数据。从通道中读数据
- 4.阻塞: 发送数据:chan <- data,阻塞的,直到另一条goroutine,读取数据来解除阻塞 读取数据:data <- chan,也是阻塞的。直到另一条goroutine,写出数据解除阻塞。
- 5.本身channel就是同步的,意味着同一时间,只能有一条goroutine来操作。
最后:通道是goroutine之间的连接,所以通道的发送和接收必须处在不同的goroutine中。