本章節關鍵詞
- CSP模型
- 無緩存Channel/有緩存Channel
- 主線程信息通知
1 定義
在講 channel 之前,有必要先提一下 CSP 模型,傳統的併發模型主要分爲 Actor 模型和 CSP 模型,CSP 模型全稱爲 communicating sequential processes,CSP 模型由併發執行實體(進程,線程或協程),和消息通道組成,實體之間通過消息通道發送消息進行通信。和 Actor 模型不同,CSP 模型關注的是消息發送的載體,即通道,而不是發送消息的執行實體。關於 CSP 模型的更進一步的介紹,有興趣的同學可以閱讀論文 Communicating Sequential Processes,Go 語言的併發模型參考了 CSP 理論,其中執行實體對應的是 goroutine, 消息通道對應的就是 channel。 摘自:https://www.jianshu.com/p/24ede9e90490
2 用法
1.channel支持go的兩種命名方式
var c chan int
c := make(chan int) //無緩存channel 直接阻塞
c := make(chan int,3) //有緩存channel,緩存滿時,阻塞
2.channel可定義數組
var channels [10]chan int
var channels [10]chan<- int send only
var channels [10] <-chan int receive only
3.channel可作爲方法的入參
4.channel的關閉永遠由發送方close
defer close(c)
5.channel的接收
n,ok := <- c ; if !ok break //自動檢測close,不如此做會在即使close後繼續獲取o值
for n : range c{} //會自動檢測close
package main
import (
"fmt"
"time"
)
func main() {
//chanDemo()
bufferedChannel()
}
func work(id int, c chan int) {
for {
//fmt.Printf("Worker %d received %c\n", id, <-c),直接這樣接收在close後接收的值爲0值
//判斷channel關閉
n,ok := <-c
if !ok{
break
}
//或者用range接收,
/*
for n: range c{
fmt.Printf("Worker %d received %c\n", id, <-c)
}
*/
fmt.Printf("Worker %d received %c\n", id, <-c)
}
}
//channel 也可以作爲返回值
func createWorker(id int) chan<- int {
c := make(chan int)
go work(id, c)
return c //相當於此處有一個自動轉化爲只寫的channel的過程
}
//channel可以作爲參數,也可以建channel數組
/*
func worker(id int,c chan int){
for{
n := <- c
fmt.Printf("Worker %d received %d\n",id,<-c)
}
}
*/
func chanDemo() {
//var c chan int // c == nil,沒辦法用,後續用
var channels [10]chan<- int
for i := 0; i < 10; i++ {
//創建channel
/*
channels[i] = make(chan int)
go worker(i,channels[i])
*/
channels[i] = createWorker(i)
}
//發數據
for i := 0; i < 10; i++ {
channels[i] <- 'a' + i
}
for i := 0; i < 10; i++ {
channels[i] <- 'A' + i
}
time.Sleep(time.Millisecond)
//直接收數據
//n := <- c
//fmt.Println(n)//deadlock,發送的同時必須要有人收,併發收
}
//有緩衝的channel,超過緩衝會報死鎖
func bufferedChannel() {
c := make(chan int, 3)
go work(0, c)
c <- 'a'
c <- 'b'
c <- 'c'
c <- 'd'
//close(c)//永遠是在發送方close,告訴接收方發送結束
time.Sleep(1 * time.Millisecond)
}
主線程準備一個接收變量同步,gorountine結束
package main
import(
"fmt"
)
func main() {
chanDemo()
}
type worker struct{
c chan int
done chan bool
}
func chanDemo() {
var workers [10] worker
for i := 0; i < 10; i++ {
workers[i] = createWorker(i)
}
//發數據
for i := 0; i < 10; i++ {
workers[i].c <- 'a' + i
<- workers[i].done
}
/*for i := 0; i < 10; i++ {
workers[i].c <- 'A' + i
<- workers[i].done
}
*/
}
//channel 也可以作爲返回值
func createWorker(id int) worker {
c := worker{
c : make(chan int),
done : make(chan bool),
}
go doWork(id, c.c,c.done)
return c
}
func doWork(id int, c chan int,done chan bool ) {
for n := range c{
fmt.Printf("Worker %d received %c\n", id, n)
done <- true
}
}