接下來是 golang 重頭戲之二 channel ,上一篇已經有講過 gorotuine,channel 的用途非常多,可以拿來當不同 gorotuine 的溝通通道,也可以 buffer quene,那接下來開始介紹 channel

channel

首先我們要先來試試看,如何宣告一個 channel,並且傳送一個訊息給它

package main

import (
	"fmt"
)

var message chan string

func Bot() {
	msg := <-message
	fmt.Printf("Bot Print:%s\n", msg)
}

func main() {
	message = make(chan string)

	go Bot()
	message <- "Hello World"

	fmt.Println("end")
}

https://play.golang.org/p/kdVCn2Abk11

channel 如果沒有宣告 buffer, sender 端,送進去的訊息,reciver 端沒收之前,sender 端送不進去第二則訊息,此時,sender 端會 block,在這邊要注意控制這個問題,以避免造成 deadlock。

下面我們示範一下 deadlock 情境

package main

import (
	"fmt"
)

var message chan string

func Bot() {
	msg := <-message
	fmt.Printf("Bot Print:%s\n", msg)
}

func main() {

	message = make(chan string)

	go Bot()

	message <- "first message"
	fmt.Println("first message send finish")
	message <- "second message"
	fmt.Println("second message send finish")

	fmt.Println("end")
}

https://play.golang.org/p/O_DjamN8sss

那如何在沒宣告 buffer 的情況下,排除上面的 deadlock

package main

import (
	"fmt"
	"time"
)

var message chan string

func Bot() {
    //讓bot 不斷接收訊息,就不會造成 main thread 卡死
	for msg := range message {
		fmt.Printf("Bot Print:%s\n", msg)
	}
}

func main() {

	message = make(chan string)

	go Bot()

	message <- "first message"
	fmt.Println("first message send finish")
	message <- "second message"
	fmt.Println("second message send finish")

	//加入Sleep 是為了避免 main thread提前結束,而看不到 bot 後續印的值
	time.Sleep(1*time.Second)
	fmt.Println("end")
}

https://play.golang.org/p/OSzlVjXGMIj

那如何宣告 channel 的 buffer 呢?

package main

import (
	"fmt"
)

var message chan string

func Bot() {
	msg := <-message
	fmt.Printf("Bot Print:%s\n", msg)
}

func main() {
	//這裡為宣告 5 個 channel buffer,意思就是可以quene 5個 string
	message = make(chan string, 5)

	go Bot()

	message <- "first message"
	fmt.Println("first message send finish")
	message <- "second message"
	fmt.Println("second message send finish")

	fmt.Println("end")
}

https://play.golang.org/p/NpBkrnKGfIQ

由上面可以看到,運用 buffer 宣告也可以解決前面範例 deadlock 的問題。

Do not communicate by sharing memory; instead, share memory by communicating.

上面這句話,是引言自,golang 官方 blog,有一篇講解 channel 的使用時機、跟他的設計精神,有興趣的可以前往閱讀。