内容简介:通道类型是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
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
人人都是产品经理
苏杰 / 电子工业出版社 / 2014-9-1 / CNY 55.00
《人人都是产品经理(纪念版)》为经典畅销书《人人都是产品经理》的内容升级版本。对于大量成长起来的优秀互联网产品经理,为数不少想投身产品工作的其他岗位从业者,以及更多有志从事这一职业的学生而言,这本书曾是他们记忆深刻的启蒙读物、思想基石和行动手册。作者以分享经历与体会为出发点,以“朋友间聊聊如何做产品”的语气,将自己数年产品工作过程中学到的思维方法与做事方式,及其它们对自己的帮助,系统性地梳理为用户......一起来看看 《人人都是产品经理》 这本书的介绍吧!