[Go]通道(channel)的基本操作

  通道类型是Go语言自带的、唯一一个可以满足并发安全性的类型,在声明并初始化一个通道时,需要用到内建函数make,传给make函数的第一个参数应该代表通道的具体类型的类型字面量。

  如类型字面量 chan int,其中chan表示通道类型的关键字,而int说明了该通道类型的元素类型。

  在初始化通道时,make函数除了必须接受这样的字面量作为参数,还可以接收一个int类型的参数。后者是可选的,用于表示通道的容量(通道最多缓存多少个元素值),不能小于0。当容量为0时称其为非缓冲通道,当容量大于0时,可以称为缓冲通道

  一个通道相当于一个先进先出(FIFO)的队列。元素值的发送和接收都需要用到操作符  <-

 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6     ch1 := make(chan int, 3)
 7     ch1 <- 2
 8     ch1 <- 1
 9     ch1 <-3
10     elem1 := <-ch1
11     fmt.Printf("first element :%v\n", elem1)
12 }

  由于该通道容量为3,所以可以在通道不包含任何元素值的时候,连续地向该通道发送三个值,此时这三个值都会被缓存在通道之中。当从通道接收元素值的时候,同样要用接送操作符 <-

1、对通道的发送和接收操作都有哪些基本的特性?

  1)对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的

    在同一时刻,Go语言的运行时系统只会执行对同一个通道的任意个发送操作中的某一个,知道这个元素值被完全复制进该通道之后,其他针对该通道的发送操作才可能被执行

    类似的,在同一时刻,运行时系统也只会执行对同一个通道的任意个接收操作中的某一个,直到这个元素值完全被移除该通道之后,其他针对该通道的接收操作才可能被执行。

    另外,对于通道中的同一个元素值来说,发送操作和接收操作也是互斥的,虽会出现正在被复制进通道但还未复制完成的元素值,但此时它绝不会被想接收它的一方看到和取走

扫描二维码关注公众号,回复: 3028340 查看本文章

    并且,元素值从外界进入通道时会被复制,进入通道的并不是接收操作符右边那个元素值,而是它的副本。

  2)发送操作和接收操作中对元素值的处理都是不可分割的

    不可分割的意思是处理元素值时是一气呵成不会被打断的

    发送操作要么还没复制元素值,要么已经复制完毕,绝不会出现只复制一部分的情况

    接收操作在准备好元素值的副本之后,一定会删除通道中的原值,绝不会出现通道中仍有残留的情况

    对于通道中的桶一个元素值来说,它只可能是某一个发送操作放入的,同时也只可能被某一个接收操作取出

  3)发送操作在完成之前会被阻塞,接收操作也是

    发送操作包括“复制元素值”和“放置副本通道内部”两个步骤,在这两个步骤完全完成之前,发起这个发送操作的那句代码会一直阻塞在那里,在它之后的代码不会有执行的机会,直到这句代码阻塞解除。在通道完成发送操作之后,运行时系统会通知这句代码所在                 的goroutine,以使它去争取继续运行代码的机会

    接收操作包括“复制通道内的元素”,“放置副本到接收方”,“删掉原值”三个步骤,同理在这些步骤完全完成之前,发起该操作的代码也会一直阻塞。

2、发送操作和接收操作在什么时候可能被长时间阻塞

  1)缓冲通道

    如果通道已满,那么对它的所有发送操作都会被阻塞,直到通道中有元素值被接收走。通道会优先通知最早等待的那个发送操作所在的goroutine,通知的顺序总是公平的

    如果通道已空,那么对它的所以接收操作都会被阻塞,直到通道中有新的元素值出现,通道会优先通知最早等待的那个接收操作所在的goroutine,通知的顺序总是公平的

  2)非缓冲通道

    无论发送操作还是接收操作,一开始执行就会被阻塞,直到配对的操作也开始执行。即非缓冲通道是在用同步的方式传递数据,也就是说,只有收发双方对接上了,数据才会被床底,数据是直接从发送方复制到接收方的,中间并不会用非缓冲通道做中转

  3)对值为nil的通道

    不论它的具体类型是什么,对它的发送操作和接收操作都会永久地处于阻塞状态,它们所属的goroutine中的任何代码,都不会被执行。因此一定要初始化通道

3、发送操作和接收操作在什么时候会引发panic?

  对于一个已初始化,但并未关闭的通道来说,收发操作一定不会引发panic,但通道一旦关闭,再对它进行发送操作,就会引发panic。

  如果试图关闭一个已经关闭了的通道,也会引发panic

  当把接收表达式结果同时赋值给两个变量时,第二个变量的类型就是一定bool类型,它的值如果是False就说明通道已经关闭,并且再没有元素值可取。如果通道关闭时,里面还有元素值未被取出,那么接收表达式的第一个结果仍会是通道中的某一个元素值,而第二个结果值一定会是true

猜你喜欢

转载自www.cnblogs.com/yuxiaoba/p/9577212.html