Channels 通道 - Go 學習記錄

Aliliin發表於2020-06-15

基本語法和需要注意的點

  1. 語法定義
     var channel chan [type]
    • 使用 <- 傳遞資料
    • chan <- data 傳送資料到通道,向通道中寫資料
    • data <- chan 獲取通道中的資料,從通道中讀取資料
  2. 注意的點
    • 它是用於 goroutine 之間進行傳遞訊息的
    • 每個 channel 都有相關聯的資料型別, nil chan不能使用
    • channel 是在 goroutine 之間連結,資料接收和傳送必須處於不同的 goroutine
    • 非緩衝通道傳送資料和讀取資料都是阻塞的,直到另一條 goroutine執行讀取或寫完資料才會解除阻塞
    • channel 是同步的,就意味著同一時間,只能有一條 goroutine來操作
    • 不要忘記 close(channel) 關閉通道

程式碼實現:

package main

import (
    "fmt"
    "strconv"
)

func main() {

    // 建立通道
    var channel chan int
    fmt.Printf("%T,%v\n", channel, channel) // chan int,<nil>
    channel = make(chan int)
    fmt.Printf("%T,%v\n", channel, channel) // chan int,0xc00008c060

    // 通道內寫入資料
    go setData(channel)
    // 讀取通道內的資料
    for v := range channel {
        fmt.Println("讀取的資料: ", v) // 讀取的資料:0,1,2,3,4
    }

    // 非緩衝通道
    var ch1 chan int
    ch1 = make(chan int)
    go func() {
        for i := 0; i < 5; i++ {
            fmt.Println("子的 goroutine 中,i", i) // 子的 goroutine 中,i 0,1,2,3,4
        }
        // 迴圈結束後向通道中寫資料,表示結束了。
        ch1 <- 1
        fmt.Println("結束")
    }()

    data := <-ch1
    fmt.Println("main data --> ", data)

    /**
    緩衝通道(固定大小)
        接收:緩衝區資料空了會阻塞
        寫入:緩衝區資料滿了會阻塞
    */
    ch2 := make(chan int, 3)
    fmt.Println(len(ch2), cap(ch2)) // 0 ,3
    ch2 <- 1
    ch2 <- 2
    ch2 <- 3
    fmt.Println(len(ch2), cap(ch2)) // 3,3
    // 緩衝區滿了,如果需要繼續寫入資料,需要有其他的 goroutine 進行讀取(佇列的結構來讀取)
    // ch2 <- 4
    ch3 := make(chan string, 3)
    fmt.Println(len(ch3), cap(ch3)) // 0 ,3
    go setStringData(ch3, 3)
    for {
        v, ok := <-ch3
        if !ok {
            fmt.Println("讀取完畢", ok) // 讀取完畢 false
            break
        }
        fmt.Println("讀取的資料是:", v) // 讀取的資料是: 0,1,2
    }

    /**
    雙向通道
        chan ch
            chan <- data 寫入資料
            data <- chan 讀取資料
    */
    ch4 := make(chan string)
    isDone := make(chan bool)
    go SendString(ch4, isDone)
    data1 := <-ch4        // 讀取
    fmt.Println(data1)    // golang
    ch4 <- "learn golang" // 傳送

    <-isDone // 判斷這個來看主程式結束

    /**
    單向通道:定向
        chan <- Write 只支援寫
        <- chan Read 只能讀
    */
    singleChanWrite := make(chan<- int) // 只能寫,不能讀
    singleChanRead := make(<-chan int)  // 只能讀,不能寫

    fmt.Println("main over")
}

func setData(ch chan int) {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch) // 通知對方,通道關閉
}

func setStringData(ch chan string, number int) {
    for i := 0; i < number; i++ {
        ch <- strconv.Itoa(i)
    }
    close(ch) // 通知對方,通道關閉
}

func SendString(ch chan string, isDone chan bool) {
    ch <- "golang"                            // 傳送
    data2 := <-ch                             // 讀取資料
    fmt.Println("main goroutine 傳來: ", data2) // main goroutine 傳來:   learn golang

    isDone <- true // 限制主程式過快的結束執行
}

*/

如想看學習記錄同步的練習程式碼移步 GitHub

本作品採用《CC 協議》,轉載必須註明作者和本文連結

高永立

相關文章