在golang裡可使用channel在多個執行緒與主程式之間傳送資料,channel可設定不同型態的buffer,並指定緩衝區大小

建立channel

使用make配置空間,第一個參數使用chan指定為通道類型,後面接上channel的型態,第二個參數可加可不加,用來宣告buffer的大小

ch := make(chan int)
ch := make(chan int,5)

須注意buffer的預設大小為零,若無指定buffer大小則發送方與接收方需同時準備好才可傳值,否則會造成deadlock(死結)

//OK(buffer為0)
ch := make(chan int)
defer close(ch)
go func(){
    ch <- 7
}()

fmt.Println(<-ch)

//ERROR(buffer為0)
ch := make(chan int)
defer close(ch)
ch <- 7

fmt.Println(<-ch)

//OK(buffer為1)
ch := make(chan int,1)
defer close(ch)
ch <- 7

fmt.Println(<-ch)

使用channel傳遞數值

傳入channel

將箭頭由數值指向channel,代表將值傳入到channel內

ch <- 7

傳出channel

將箭頭由channel指向目的地,代表將數值由channel傳出

var result int
result <- ch
fmt.Println(result)

等待所有goroutine結束

有時會遇到明明寫好了goroutine,但在最後將要把數據輸出時卻沒出現任何數據,這時就有可能是因為執行緒尚未結束運算而已經先呼叫close(ch)導致無法使用ch,所以輸出時不會得到channel傳來的任何資訊,當然也不會輸出任何東西

func foo(ch chan int, val int) {
    ch <- val
}

func main() {
    ch := make(chan int, 5)
    for i := 0; i < 5; i++ {
        foo(ch, i)
    }
    close(ch)

    for ele := range ch {
        fmt.Println(ele)
    }
}

我們可以使用WaitGroup控制,等到所有執行緒都結束後再繼續往下執行

var wg sync.WaitGroup

func foo(ch chan int, val int) {
    defer wg.Done()
    ch <- val
}

func main() {
    ch := make(chan int, 5)
    for i := 0; i < 5; i++ {
        wg.Add(1)
        foo(ch, i)
    }
    wg.Wait()
    close(ch)

    for ele := range ch {
        fmt.Println(ele)
    }
}