内容简介:通道类型是Go自带的,相当于是一个先进先出的队列,同时唯一一个可以满足并发安全性的类型。声明一个通道类型变量的时候,首先需要确定通道类型的元素类型,然后还要确定通道的容量,当然默认容量是0。使用make进行初始化,如下所示:如果不指定容量,默认通道的容量是0,这种通道也成为非缓冲通道。
通道类型是 Go 自带的,相当于是一个先进先出的队列,同时唯一一个可以满足并发安全性的类型。声明一个通道类型变量的时候,首先需要确定通道类型的元素类型,然后还要确定通道的容量,当然默认容量是0。
初始化
使用make进行初始化,如下所示:
c := make(chan int) c := make(chan string, 10)
如果不指定容量,默认通道的容量是0,这种通道也成为非缓冲通道。
通道的发送和接收特性
-
对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的。
简单来说就是在同一时刻,Go的运行系统只会执行对同一个通道的任意个发送操作中的某一个,直到这个元素值被完全复制进该通道之后,其他发送操作才会执行。针对接收操作也是这样。
对于通道中的同一个值,发送操作和接收操作也是互斥的。如正在被复制进通道但还未复制完成的元素值,这时接收方也不会看到和取走。
tips
元素值从外界进入通道会被复制。也就是说进入通道的并不是在接收操作符右边的那个元素值,而是他的副本。
-
发送操作和接收操作中对元素值的处理都是不可分割的。
不可分割意思就是发送操作要么还没复制元素,要么已经复制完毕,不会出现值只复制了一部分的情况。
-
发送操作在完全完成之前会被阻塞。接收操作也是如此。
发送操作包括,“复制元素值”,“放置副本到通道内” 二个步骤。在这二个步骤完成之前,发送操作会一直阻塞,他之后的代码是不会执行的。
接收操作包括“复制通道内元素值”,“放置副本到接收方”,“删除原值” 三个操作。这三个操作在完成之前也是会一直阻塞的。
tips: 上面讲的复制都属于浅拷贝。浅拷贝只是拷贝值以及值中直接包含的东西,深拷贝就是把所有深层次的结构一并拷贝,Golang只有浅拷贝。
发送操作和接收操作在什么时候会被阻塞呢
对于缓存通道
- 如果通道已满,所有的发送操作就会阻塞,直到通道中有元素被取走
- 如果通道已空,所有的接收操作就会阻塞,直到通道中有新的元素
对于非缓存通道
- 无论发送操作还是接受操作一开始就是阻塞的,只有配对的操作出现才会开始执行。
收发操作何时会引起panic
-
通道关闭,在进行发送操作会引发panic
-
关闭一个已经关闭的通道也会引发panic
更具体地说,当我们把接收表达式的结果同时赋给两个变量时,第二个变量的类型就是一定bool类型。它的值如果为false就说明通道已经关闭,并且再没有元素值可取了。
注意,如果通道关闭时,里面还有元素值未被取出,那么接收表达式的第一个结果,仍会是通道中的某一个元素值,而第二个结果值一定会是true。因此,通过接收表达式的第二个结果值,来判断通道是否关闭是可能有延时的。
package main import "fmt" func main() { ch1 := make(chan int, 2) // 发送方。 go func() { for i := 0; i < 10; i++ { fmt.Printf("Sender: sending element %v...\n", i) ch1 <- i } fmt.Println("Sender: close the channel...") close(ch1) }() // 接收方。 for { elem, ok := <-ch1 if !ok { fmt.Println("Receiver: closed channel") break } fmt.Printf("Receiver: received an element: %v\n", elem) } fmt.Println("End.") }
Channel引起的死锁的常见场景
死锁是指两个或两个以上的协程的执行过程中,由于竞争资源或由于彼此通信而造成的一种阻塞的现象,若无外力作用,他们将无法推进下去,解决死锁的方法是加锁。。结合上面讲的channel相关知识,大家可以思考一下面情况为何为引起死锁。
场景1:一个通道在一个go协程读写
func main() {
c:=make(chan int)
c<-666
<-c
}
场景二:go程开启之前使用通道
func main() {
c:=make(chan int)
c<-666
go func() {
<-c
}()
}
场景三:通道1中调用了通道2,通道2中调用通道1
func main() {
c1, c2 := make(chan int), make(chan int)
go func() {
for {
select {
case <-c1:
c2 <- 10
}
}
}()
for {
select {
case <-c2:
c1 <- 10
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Golang 关于通道 Chan 详解
- ICML 2019 | 腾讯AI Lab入选论文详解:从协同通道剪枝到多智能体强化学习
- Golang 并发,有缓存通道,通道同步案例演示
- 科普 | 菜鸟学习状态通道,Part-2:App 定制型状态通道
- golang通道定义
- 通道 | Java NIO
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Game Engine Architecture, Second Edition
Jason Gregory / A K Peters/CRC Press / 2014-8-15 / USD 69.95
A 2010 CHOICE outstanding academic title, this updated book covers the theory and practice of game engine software development. It explains practical concepts and techniques used by real game studios,......一起来看看 《Game Engine Architecture, Second Edition》 这本书的介绍吧!
HTML 编码/解码
HTML 编码/解码
XML、JSON 在线转换
在线XML、JSON转换工具