Channels

Go 言語げんごの Channel:Goroutine かん通信つうしんメカニズム。

Channel 概念

  • FIFO:Queue 構造こうぞう
  • データの受信じゅしん送信そうしん
  • Goroutines かん通信つうしんのための機能きのう

goroutine からデータをかえ必要ひつようがある場合ばあいは、Channel を使用しよう

Channel の作成

make(chan val-type)

Channel Buffering

デフォルトでは channel はバッファなし

Unbuffered Channel

  • きの両方りょうほう完了かんりょうするまで main は終了しゅうりょうできない
  • バッファなし channel はあたい格納かくのうする容量ようりょうがない
  • 送信者そうしんしゃ受信者じゅしんしゃあたいるまでブロックする
  • goroutine かん同期どうき通信つうしん使用しよう
  • 送信者そうしんしゃ受信者じゅしんしゃ両方りょうほう準備じゅんびできてからあたい交換こうかん
func main(){
    ch := make(chan int)

    go func(){
        ch <- 42
    }()

    fmt.Println(<-ch)
}

Buffered Channel

  • きはことなる Goroutine 環境かんきょうおこな必要ひつようがある
  • あたい格納かくのうする定義ていぎされた容量ようりょう
  • 送信者そうしんしゃは channel が満杯まんぱいときだけブロック
  • 受信者じゅしんしゃは channel がからときだけブロック
  • 送信者そうしんしゃ受信者じゅしんしゃのタイミングを分離ぶんりし、ある程度ていど非同期性ひどうきせい提供ていきょう
func main(){
    ch := make(chan int, 2)

    ch <- 100
    ch <- 10

    result1 := <-ch
    result2 := <-ch
}

Buffered と Unbuffered の使い分け

Buffered Channel は:起動きどうした goroutine のかずかっている、goroutine のかず制限せいげんしたい、またはキューにれる作業さぎょうりょう制限せいげんしたい場合ばあいてきしている。

Channel Operations

値の送信

  • <- は channel 送信そうしん演算子えんざんし
  • v は channel ch要素ようそかた代入だいにゅう可能かのうあたい
ch <- v

値の受信

  • <- は channel 受信じゅしん演算子えんざんし
  • val は channel からったデータを格納かくのうする変数へんすう
val := <-ch

Channel を閉じる

  • close 関数かんすう引数ひきすうは channel あたい
close(ch)
  • ok が true なら channel はひらいている
  • ok が false なら channel はじており、あたいがない
v, ok := <-ch

Channel 容量の確認

cap(ch)

Channel 長さの確認

len(ch)

Deadlock、Panic、Resource Leak Cases

Channel Deadlock

// Case 1: 単一 Goroutine がバッファなし Channel に書き込み
func deadlock1() {
    ch := make(chan int)
    ch <- 1  // deadlock: 受信者がいない
}

// Case 2: 単一 Goroutine がバッファなし Channel から読み取り
func deadlock2() {
    ch := make(chan int)
    <-ch  // deadlock: 送信者がいない
}

// Case 3: 循環依存
func deadlock3() {
    ch1, ch2 := make(chan int), make(chan int)
    go func() {
        ch1 <- 1  // ch2 を待つ
        <-ch2
    }()
    go func() {
        ch2 <- 1  // ch1 を待つ
        <-ch1
    }()
}

// Case 4: バッファが満杯
func deadlock4() {
    ch := make(chan int, 1)
    ch <- 1
    ch <- 2  // deadlock: バッファが満杯
}

// Case 5: nil channel 操作
func deadlock5() {
    var ch chan int
    <-ch  // deadlock: nil channel
}

// Case 6: select 全てブロック
func deadlock6() {
    ch := make(chan int)
    select {
    case <-ch:
    case ch <- 1:
    }  // deadlock: default なし
}

// Case 7: range で channel が閉じられていない
func deadlock7() {
    ch := make(chan int)
    for v := range ch {  // deadlock: 閉じられていない
    }
}

// Case 8: mutex の誤用
func deadlock8() {
    var mu sync.Mutex
    ch := make(chan int)
    mu.Lock()
    ch <- 1  // deadlock: mutex が解除されない
}

Channel Panic

// Case 1: 閉じた後に書き込み
func panic1() {
    ch := make(chan int)
    close(ch)
    ch <- 1  // panic: 閉じた channel に書き込み
}

// Case 2: 二重クローズ
func panic2() {
    ch := make(chan int)
    close(ch)
    close(ch)  // panic: 二重クローズ
}

// Case 3: 閉じた channel に送信
func panic3() {
    ch := make(chan int)
    go func() {
        close(ch)
    }()
    ch <- 1  // panic の可能性: 閉じた channel に送信
}

// Case 4: nil channel クローズ
func panic4() {
    var ch chan int
    close(ch)  // panic: nil channel クローズ
}

// Case 5: 閉じた channel で select 送信
func panic5() {
    ch := make(chan int)
    close(ch)
    select {
    case ch <- 1:  // panic: 閉じた channel に送信
    default:
    }
}

Resource Leak

// Case 1: Goroutine リーク
func leak1() {
    ch := make(chan int)
    go func() {
        <-ch  // goroutine が永遠にブロック
    }()
}

// Case 2: 受信者が送信者より多い
func leak2() {
    ch := make(chan int, 1)
    ch <- 1
    close(ch)
    <-ch
    <-ch  // deadlock にならないが、ゼロ値を受信
}

// Case 3: Context キャンセルが処理されない
func leak3() {
    ctx, cancel := context.WithCancel(context.Background())
    ch := make(chan int)
    go func() {
        select {
        case <-ctx.Done():
            return
        case ch <- 1:
        }
    }()
    cancel()  // goroutine がリークする可能性
}

Select

  • 複数ふくすうの channel 操作そうさつことができる
  • ChannelGoroutinesわせて同期どうき並行へいこう処理しょり管理かんりする強力きょうりょくなツール

select vs switch

selectswitch
ブロック可能かのう(channel で使用しよう非ブロッキング
決定的けっていてき(ランダムに case を選択せんたく決定的けっていてき順番じゅんばん一致いっちする case を選択せんたく

関連トピック