一 channel介绍单纯地将函数并发执行是没有意义的 。函数与函数间需要交换数据才能体现并发执行函数的意义 。
虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题 。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁 , 这种做法势必造成性能问题 。
Go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信 。
如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接 。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制 。
Go 语言中的通道(channel)是一种特殊的类型 。通道像一个传送带或者队列 , 总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序 。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型 。
二 channel类型channel是一种类型,一种引用类型 。声明通道类型的格式如下:
var 变量 chan 元素类型
举几个例子:
var ch1 chan int// 声明一个传递整型的通道var ch2 chan bool// 声明一个传递布尔型的通道var ch3 chan []int // 声明一个传递int切片的通道
三 创建channel通道是引用类型,通道类型的空值是nil 。
var ch chan intfmt.Println(ch) // <nil>
声明的通道后需要使用make函数初始化之后才能使用 。
创建channel的格式如下:
make(chan 元素类型, [缓冲大小])
channel的缓冲大小是可选的 。
举几个例子:
ch4 := make(chan int)ch5 := make(chan bool)ch6 := make(chan []int)
四 channel操作通道有发送(send)、接收(receive)和关闭(close)三种操作 。
发送和接收都使用<-符号 。
现在我们先使用以下语句定义一个通道:
ch := make(chan int)
发送将一个值发送到通道中 。
ch <- 10 // 把10发送到ch中
接收从一个通道中接收值 。
x := <- ch // 从ch中接收值并赋值给变量x<-ch// 从ch中接收值,忽略结果
关闭我们通过调用内置的close函数来关闭通道 。
close(ch)
关于关闭通道需要注意的事情是,只有在通知接收方goroutine所有的数据都发送完毕的时候才需要关闭通道 。通道是可以被垃圾回收机制回收的,它和关闭文件是不一样的,在结束操作之后关闭文件是必须要做的,但关闭通道不是必须的 。
关闭后的通道有以下特点:
1.对一个关闭的通道再发送值就会导致panic 。2.对一个关闭的通道进行接收会一直获取值直到通道为空 。3.对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值 。4.关闭一个已经关闭的通道会导致panic 。
五 无缓冲的通道
![Go_Channel详解](http://img.zhejianglong.com/231018/0644363248-0.png)
文章插图
无缓冲的通道又称为阻塞的通道 。我们来看一下下面的代码:
func main() {ch := make(chan int)ch <- 10fmt.Println("发送成功")}
上面这段代码能够通过编译,但是执行的时候会出现以下错误: fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:main.main().../src/github.com/pprof/studygo/day06/channel02/main.go:8 +0x54
为什么会出现deadlock错误呢?因为我们使用ch := make(chan int)创建的是无缓冲的通道,无缓冲的通道只有在有人接收值的时候才能发送值 。就像你住的小区没有快递柜和代收点 , 快递员给你打电话必须要把这个物品送到你的手中,简单来说就是无缓冲的通道必须有接收才能发送 。
上面的代码会阻塞在ch <- 10这一行代码形成死锁,那如何解决这个问题呢?
一种方法是启用一个goroutine去接收值 , 例如:
func recv(c chan int) {ret := <-cfmt.Println("接收成功", ret)}func main() {ch := make(chan int)go recv(ch) // 启用goroutine从通道接收值ch <- 10fmt.Println("发送成功")}
无缓冲通道上的发送操作会阻塞,直到另一个goroutine在该通道上执行接收操作 , 这时值才能发送成功,两个goroutine将继续执行 。相反,如果接收操作先执行,接收方的goroutine将阻塞,直到另一个goroutine在该通道上发送一个值 。使用无缓冲通道进行通信将导致发送和接收的goroutine同步化 。因此,无缓冲通道也被称为同步通道 。
六 有缓冲的通道解决上面问题的方法还有一种就是使用有缓冲区的通道 。
推荐阅读
- gitee仓库上传文件的步骤
- 黑色沙漠手游10月25日微信每日一题答案是什么
- 王者荣耀10月25日微信每日一题答案是什么
- 为什么九一八又称柳条湖事件 柳条湖事件
- Docker | 容器数据卷详解
- MyBatis之ResultMap的association和collection标签详解
- 完 golang开发:go并发的建议
- 新剑侠情缘10月25日微信每日一题答案是什么
- 中国10大钻戒品牌是什么, 你最喜欢哪一款?
- 笔仙怎么玩……一个人又该怎么玩(笔仙的步骤)