目录
- 前言
- 正文
- 结尾
前言
前面讲了 Golang 语言中通道的概念,大家对通道应该有了基本的认识,至少应该知道通道是用来传输数据的。
正文
通道既然是用来传输数据的,那么这些数据一定有自己的类型,是的,没错。同样管道也有自己的类型,只是在数据类型的前面多了一个 chan 标识,比如 chan int,chan string等。
通道既然是用来传输数据的,那么通道会不会有方向的区别呢?哈哈,是的。通道确实是有方向的,只不过,我们一般都是常见双向通道。注意,这里说的方向是数据的写入和读取。
这时,可能有人会问:是不是有些通道,只能来读数据?有些通道,只能来写数据? 答案是 yes 。
那么如何声明和定义只读通道和只写通道呢?
接下来,看一段代码:
ch1 := make(chan int) // 一般情况下,我们定义的双向通道
ch2 := make(chan<- int) // 这是一个只写通道,只能写入int类型的数据
ch3 := make(<-chan int) // 这是一个只读通道,只能读取int类型的数据
好的,明白来了吧。
那么通道还有别的类型吗?
有的,通道还有一种类型————缓冲通道。
一般创建的通道,其实也是有缓冲区的,只是缓冲区大小为0。嘿嘿,就是没有嘛!
缓冲通道怎么声明和定义呢?我们再来看一段代码:
ch1 := make(chan int) // 一般情况下,我们定义的缓冲区为0的通道
ch2 := make(chan int, 10) // 我们定义了一个缓冲区大小为10的通道,意思就是说我们可以写入11个数据,不理解的话,可以好好思考一下呦!
那么缓冲通道有什么特殊的作用呢?一般的非缓冲通道,每次读写都是阻塞的,很容易造效率问题,而缓冲通道就可以在一定程度上避免这个问题。
下面我们通过一个例子,来看看缓冲通道是怎么工作的吧。
实例代码:
package main
import (
"fmt"
)
func main() {
// 定义一个缓冲区大小为5的通道
ch1 := make(chan int, 5)
// 开启子协程goroutine写入数据
go func() {
for i := 0; i < 11; i++ {
ch1 <- i
fmt.Println("子协程写入数据:", i)
}
close(ch1) //关闭通道
}()
// 主协程读取数据
for {
v, ok := <-ch1
if !ok {
fmt.Println("读取结束", ok)
break
}
fmt.Println("主协程读取到的数据为:", v)
}
fmt.Println("主协程结束")
}
代码执行过程:
子协程写入数据: 0
子协程写入数据: 1
子协程写入数据: 2
子协程写入数据: 3
子协程写入数据: 4
子协程写入数据: 5
主协程读取到的数据为: 0
主协程读取到的数据为: 1
主协程读取到的数据为: 2
主协程读取到的数据为: 3
主协程读取到的数据为: 4
主协程读取到的数据为: 5
主协程读取到的数据为: 6
子协程写入数据: 6
子协程写入数据: 7
子协程写入数据: 8
子协程写入数据: 9
子协程写入数据: 10
主协程读取到的数据为: 7
主协程读取到的数据为: 8
主协程读取到的数据为: 9
主协程读取到的数据为: 10
读取结束 false
主协程结束
我们可以看到,缓冲通道能够连续写入数据,即使没有被读取,也不会被阻塞。这样就能够避免像非缓冲通道那样一写一读的死板工作方式,当然这也需要看具体的使用场景,不能一概而论。
结尾
好了,今天关于通道的入门知识就讲这些,主要理解通道是有“方向”概念的,另外就是通道可以有缓冲区。
PS:掘金编辑器的主题模版很好用,赞一个👍