无缓存的通道
是指在接收前没有能力保存任何值的通道
这种类型的通道要求goroutine和接收goroutine同时准备好,才能完成发送和接收操作,如果两个goroutine没有同时准备好,通道会导致先执行发送或接收操作的gotourine阻塞等待。
这种对通道进行发送和接收的交互行为本身就是同步的,其中任意一个操作都无法离开另一个操作单独存在。
下图展示两个goroutine如何利用无缓冲的通道来共享一个值
使用无缓存的通道在goroutine之间同步
通过图片截图无缓存channel
- 在第一步,两个goroutine都到达通道,但哪个都没有开始执行发送或者接收。
- 在第二步,左侧的goroutine将它的手伸进了通道,这模拟了向通道发送数据的行为,这时,这个goroutine会在通道中被锁住,直到交换完成。
- 在第三步,右侧的goroutine将它的手放入通道,这模拟了从通道里接收数据。这个goroutine一样也会在通道中被锁住,直到交换完成。
- 在第四步和第五步,进行交换,并最终,在第六步,两个goroutine都将他们的手从通道里拿出来,这模拟了被锁住的goroutine得到释放,两个goroutine现在都可以去做别的事情了。
无缓存的channel创建格式:
make(chan Type) // 等价于make(chan Type,0)
//如果没有指定缓冲区容量,那么该通道就是同步的,因此会阻塞到发送者准备好发送和接收者准备好接收。
package main
import (
"fmt"
"time"
)
func main() {
//创建无缓存的channel
ch := make(chan int)
//len(ch)缓冲区剩余数据个数,cap(ch)缓冲区大小
fmt.Printf("len(ch) = %d , cap(ch) = %d \n", len(ch), cap(ch))
//新建协程
go func() {
for i := 0; i < 3; i++ {
fmt.Printf("子协程:i = %d", i)
ch <- i //往chan写内容
}
}()
//延时
time.Sleep(2 * time.Second)
for i := 0; i < 3; i++ {
num := <-ch //读管道中内容,没有内容前,阻塞
fmt.Println("num = ", num)
}
}
代码流程图
网友评论