一、Channel管道
1、Channel说明
共享内存交互数据弊端
单纯地将函数并发执行是没有意义的。函数与函数间需要交互数据才能体现编发执行函数的意义 虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发送静态问题 为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势必造成性能问题 channel好处
Go语言中的通道(channel)是一种特殊的类型 通道像一个传送带或者队列,总是遵循先入先出(First In First Out)原则,保证收发数据的顺序 每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型 如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接 channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制
2、channel类型
channel是一种类型,一种引用类型 声明管道类型的格式如下
var 变量 chan 元素类型
var ch1 chan int //声明一个传递整型的管道
var ch2 chan bool //声明一个传递布尔型的管道
var che chan []int //声明一个传递int切片的管道
3、创建channel
声明的管道后需要使用make函数初始化之后才能使用 创建channel的格式如下:make(chan 元素类型,容量)
//创建一个能存储10个int类型数据的管道
ch1 := make(chan int,10)
//创建一个能存储4个bool类型数据的管道
ch2 := make(chan bool,4)
//创建一个能存储3个[]int切片类型数据的管道
ch3 := make(chan []int,3)
二、channel操作
管道有发送(send)、接收(receive)和关闭(close)三种操作 发送和接收使用<-符合 现在我们先使用以下语句定义一个管道
ch := make(chan int,3)
1、发送(将数据放在管道内)
ch <- 10 //把10发送到ch中
2、接收(从管道内取值)
x := <- ch //从ch中接收值并赋值给变量x
<- ch //从ch中接收值,忽略结果
3、关闭管道
我们通过调用内置的close函数来关闭管道:close(ch) 关于关闭管道需要注意的事情是,只有在通知接收方goroutine所有的数据都发送完毕的时候才需要关闭管道 管道是可以被垃圾回收机制回收的,它和关闭文件是不一样的,在结束操作之后关闭文件是必须要做的,但关闭管道不是必须的 关闭后的管道有以下特点:
对一个关闭的管道再发送值就是导致panic 对一个关闭的管道进行接收会一直获取值直到管道为空 对一个关闭的并且没有值的管道执行接收操作会得到对应类型的零值 关闭一个已经关闭的管道会导致panic
4、管道阻塞
1、无缓冲的管道
如果创建管道的时候没有指定容量,那么我们可以叫这个管道为无缓冲的管道 无缓冲的管道有称为阻塞的管道
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 10
fmt.Println("发送成功")
}
/*
-- 面这段代码能够通过编译,但是执行的时候会出现以下错误
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
E:/_000/Go/Code/demo1.go:6 +0x5f
*/
2、有缓冲的管道
解决上面问题的方法还有一种就是使用有缓冲区的管道 我们可以在使用make函数初始化管道的时候为其指定管道的容量 只要管道的容量大于零,那么该管道