目录
0、几个概念
1、一个通道发送和接收数据,默认是阻塞的。
2、关闭通道和通道上范围循环
(1)关闭通道
(2)通道上范围循环遍历
3、缓冲通道
(1)非缓冲通道
(2)缓冲通道
4、定向通道
(1)单向 channel 变量的声明
(2)time包中的单向通道相关函数
5、Select语句
6、CSP并发模型
7、并发编程实例
(1)请完成goroutine和channel协调工作的案例
(2)统计素数
(3)计算累加和
(1)进程/线程
(2)并发/并行
(3)协程/线程
(4)Goroutine
(5)channel
使用内置函数close可以关闭channel,当channel关闭后,就不能再向channel写数据了,但是仍然可以从该channel读取数据
close的目的就是用来通知对方这个通道是关闭的,以此来结束循环
关闭 channel 非常简单,直接使用 Go语言内置的 close() 函数即可:
close(ch)
在介绍了如何关闭 channel 之后,我们就多了一个问题:如何判断一个 channel 是否已经被关闭?我们可以在读取的时候使用多重返回值的方式:
x, ok := <-ch
这个用法与 map 中的按键获取 value 的过程比较类似,只需要看第二个 bool 返回值即可,如果返回值是 false 则表示 ch 已经被关闭。
管道不能使用普通的for循环
在遍历时,如果channel没关闭,则会出现deadlock的错误:fatal error: all goroutines are asleep - deadlock!
在遍历时,如果channel已经关闭,则会正常遍历数据,遍历完后,就会退出遍历
以上介绍的通道都没有缓冲,发送和接收到一个未缓冲的通道是阻塞的。
一次发送操作对应一次接收操作,对于一个goroutine来讲,它的一次发送,在另一个goroutine接收之前都是阻塞的。同样的,对于接收来讲,在另一个goroutine发送之前,它也是阻塞的
缓冲通道就是指一个通道带有缓冲区。发送到一个缓冲通道只有在缓冲区满时才被阻塞。类似地,从缓冲通道接收的信息只有在缓冲区为空时才会被阻塞。带缓冲通道在很多特性上和无缓冲通道是类似的。无缓冲通道可以看作是长度永远为 0 的带缓冲通道。
因此根据这个特性,带缓冲通道在下面列举的情况下依然会发生阻塞:
如何创建带缓冲的通道呢——通道实例 := make(chan 通道类型, 缓冲大小)
为什么Go语言对通道要限制长度而不提供无限长度的通道?
我们知道通道(channel)是在两个 goroutine 间通信的桥梁。使用 goroutine 的代码必然有一方提供数据,一方消费数据。当提供数据一方的数据供给速度大于消费方的数据处理速度时,如果通道不限制长度,那么内存将不断膨胀直到应用崩溃。因此,限制通道的长度有利于约束数据提供方的供给速度,供给数据量必须在消费方处理量+通道长度的范围内,才能正常地处理数据。
我们在将一个 channel 变量传递到一个函数时,可以通过将其指定为单向 channel 变量,从而限制该函数中可以对此 channel 的操作,比如只能往这个 channel 写,或者只能从这个 channel 读。
单向 channel 变量的声明非常简单,只能发送的通道类型为chan<-
,只能接收的通道类型为<-chan
,格式如下:
time 包中的计时器会返回一个 timer 实例,代码如下:
timer := time.NewTimer(time.Second)
timer的Timer类型定义如下:
type Timer struct {
C <-chan Time
r runtimeTimer
}
第 2 行中 C 通道的类型就是一种只能接收的单向通道。如果此处不进行通道方向约束,一旦外部向通道发送数据,将会造成其他使用到计时器的地方逻辑产生混乱。因此,单向通道有利于代码接口的严谨性。
NewTimer和After方法差不多,只是返回值不同;After直接返回通道
select 的用法与 switch 语言非常类似,由 select 开始一个新的选择块,每个选择条件由 case 语句来描述。与 switch 语句相比,select 有比较多的限制,其中最大的一条限制就是每个 case 语句里必须是一个 IO 操作,select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到case可运行。
在一个 select 语句中,Go语言会按顺序从头至尾评估每一个发送和接收的语句。
如果其中的任意一语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用。
如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有如下两种可能的情况:
CSP 并发模型是上个世纪七十年代提出的,用于描述两个独立的并发实体通过共享 channel(管道)进行通信的并发模型。但是Go语言并没有完全实现了 CSP 并发模型的所有理论,仅仅是实现了 process 和 channel 这两个概念。process 就是Go语言中的 goroutine,每个 goroutine 之间是通过 channel 通讯来实现数据共享。
具体要求:
以下两种写法均可
或者: