Go語言精髓 • 【第6章 Channel通道】

本章節關鍵詞

  • 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
	}
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章