## channel
**不要通过共享内存来通信,而要通过通信来实现内存共享。**
这就是Go语言的并发哲学,他依赖于CSP,基于channel实现。
## channel的操作
channel的操作分为创建、发送、接收、关闭等4个操作,下面就从源码和流程方面分开展示
## 创建chan
```
//无缓冲的通道
ch1 := make(chan int)
//有缓冲的通道
ch2 := make(chan int , 1)
```
## 一、不同协程之间如何通讯
* 全局变量加锁同步
* channel
1、改进使用全局变量加锁同步改进程序
* 因为没有对全局变量加锁,因此会出现资源夺取问题,代码会出现错误,提示concurrent map writes
* 加入互斥锁
2、全局变量加锁同步缺陷
* 主线程在等待所有goroutine全部完成的时间很难确定
* 如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有goroutine处于工作状态,这时也会随着主线程的结束而结束
* 不利于多个协程对全局变量的读写操作
基于以上的缺陷我们可以使用管道来解决
## 二、管道基本介绍
* 管道本质介绍一个数据结构-队列
* 数据是先进先出
* 线程安全,无需加锁
* 管道有类型
## 三、管道基本使用
## 四、管道关闭和遍历
#### 1、关闭
使用内置函数close可以关闭channel,关闭后,就不能写入数据,但可读
#### 2、遍历
* 在使用for--range遍历时,如果channel没有关闭,则回出现deadlock错误
* 在使用for--range遍历时,如果channel已经关闭,则会正常遍历数据
```
package main
import "fmt"
func main() {
//定义管道
var intChan chan int
intChan =make(chan int,3)
//写入数据
intChan<-10
intChan<-20
intChan<-30
//遍历
close(intChan) //关闭管道
for value := range intChan {
fmt.Printf("%d\t",value) //10 20 30
}
}
```
## 案例
#### 案例1
1)启动一个协程,将1-2000的数放到一个channel中,比如numChan
2)启动8个协程,从numChan中取出数(比如n),并计算1+...+的值,并存放到resChan
3)最后8个协程协同完成工作后,再遍历resChan,显示结果[如res[1]=1 .. res[10]=55 ..]
```
package main
import "fmt"
func main() {
numChan := make(chan int, 2000)
resChan := make(chan int, 2000)
exitChan := make(chan bool, 8)
go putNum(numChan) //存放数据
//开启八个协程
for i := 0; i < 8; i++ {
go add(numChan, resChan, exitChan)
}
go func() {
for i:=0;i<8 ;i++ {
<-exitChan
}
close(resChan)
}()
for i := 1; i <=2000 ; i++ {
fmt.Printf("resChan[%d]=%d\n", i, <-resChan)
}
}
func putNum(numChan chan int) {
for i := 1; i <= 2000; i++ {
numChan <- i
}
close(numChan)
}
func add(numChan chan int, resChan chan int, exitChan chan bool) {
for {
n,ok := <-numChan
if !ok{
break
}
res := 0
for i := 1; i <= n; i++ {
res += i
}
resChan <- res
}
exitChan<-true
}
```
推荐:[https://juejin.cn/post/7142386254641168397](https://juejin.cn/post/7142386254641168397)