## 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)