go语言学习笔记(8) 通道的基本操作

1.什么是通道,通道有什么特点,通道怎么声明初始化
通道(channel)与goroutine一起代表了Go语言特有的并发变成模式,正式因为通道”Don’t communicate by sharing memory; share memory by communicating”这句话得以实现。通道主要是用来在多个goroutine之间传递数据。
通道类型是Go语言自带的唯一一个可以满足并发安全性的类型,我们通过make来声明初始化chan,因为引用类型的变量需要通过make来初始化,声明通道类型的变量的类型可以通过 chan type来进行通道类型的声明。
初始化通道的时候,可以向make内再传入一个int类型参数来表明通道的容量,来指明通道最多可以缓存多个元素值。这个参数不能小于零。
通道容量为0时通道为非缓冲通道。当容量大于0时通道为缓冲通道,非缓冲通道和缓冲通道数据传递方式不同。
通道类似于先进先出的队列,通道中的各个元素都是严格按照发送的顺序排列的,先被发送的元素值一定先被接受,元素的发送和接收都是通过<-来实现的。
例子:
package main

import "fmt"

func main() {
ch1 := make(chan int, 3)//初始化一个缓存为3的int类型通道
ch1 <- 2
ch1 <- 1
ch1 <- 3//通道发送,在被接受之前通道内最多存在三个元素
elem1 := <-ch1//通道的接收
fmt.Printf("The first element received from channel ch1: %v\n",
elem1)

}
2.通道的发送和接收有哪些特性
(1)对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的
在同一时刻,Go语言运行时系统,只会执行对同一个通道任意个发送操作的其中一个。知道这个发送操作完全结束后,其他针对该通道的发送操作才能被执行。
在同一时刻,运行时系统也只会执行,对同一个通道仍意个接收操作中的某一个。直到这个接收操作执行完后其他针对该通道的接收操作才能够被执行。即使这些操作是并发执行也是如此。
送操作与接收操作之间也是互斥的,一个发送操作没有完成,是无法执行一个与之对应的接收操作的。元素值进入通道
时会被复制,所以进入通道的不是这个元素值而是这个元素值的副本。并且元素值从通道进入外界时,也会发生两个操作,通道内元素的删除,以及该元素的复制。
(2)发送和接收中的元素处理是不可分割的
通道发送和接收元素值都是一气呵成的,是不会被打断的。
例如,发送操作要么还没复制元素值,要么已经复制完毕,绝不会出现只复制了一部分的情况。

对通道中的同一个元素值来说,它只可能被某一个元素值放入,也只可能被某一个接收操作取出。
(3)发送操作在完全发送前会被阻塞,接收操作也是如此
发送操作包括了“复制元素值”和“放置副本到通道内部这两个步骤”,在这两个步骤完成前,这个发送操作的那句代码会一直阻塞在那里,这时候它之后的代码没有执行机会,直到不再阻塞,在通道完成发送操作后,运行时系统会通知这句代码所在的gorountine,来争取继续运行代码的机会。
另外,接收操作通常包含了“复制通道内的元素值”“放置副本到接收方”“删掉原值”三个步骤。
在所有这些步骤完全完成之前,发起该操作的代码也会一直阻塞,直到该代码所在的 goroutine 收到了运行时系统的通知并重新获得运行机会为止。
如此阻塞代码其实就是为了实现操作的互斥,和元素的完整。

3.发送和接收操作在什么时候会被长时间阻塞。

缓冲通道当通道已满的时候,那么对它的所有发送操作都会被阻塞,直到通道中有元素被接走。这是通道会优先通知最早因此等待、那么发送操作所在的gorountine,后者会再次执行发送操作。由于发送操作在这种情况被阻塞后,它们所在的gorountine就会顺序的进入通道内部的发送等待队列,所以通知的顺序总是公平的。
如果通道已空,那么所有接收操作也会被阻塞,直到通道中有新元素出现。
非缓冲通道,无论是发送操作还是接收操作,一开始执行就会被阻塞,直到配对的操作也开始执行。所以非缓冲通道是通过同步的方式传递数据。而缓冲通道是在用异步的方式传递数据。大多数情况下,缓冲通道就相当于收发双方的中间件,元素会先复制进入缓冲通道,再由缓冲通道赋值给接收方。但是当发送操作发现由等待的接收操作就会直接复制给接收方。
对于值为nil的通道,对他的发送和接收操作都会处于永久的阻塞状态。所以一定要通过make初始化通道。

3.发送和接收操作什么时候会引发panic
对于一个已经初始化但未关闭的通道来说收发操作一定不会引发panic,但是通道一旦关闭,再对他进行收发操作,就会引发panic。
关闭一个已经关闭的通道也会出错,我们可以在接收端通过 value,ok = <- chan的形式来检测通道是否关闭,如果ok为false则表明通道未关闭,通过通道已关闭但是其中还有值,ok依旧为true,value则为其中的值。通过这种方式判断通道是否关闭是可能有延时的。

由于这种特性,我们最好要在发送方关闭通道,不要再接收方关闭通道。
代码示例: github.com/GodShuning/…


转载于:https://juejin.im/post/5b9c76bd5188255c8138e203

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值