0Pricing
Go Academy · レッスン

バッファなしチャネル

ゴルーチン間の同期的な受け渡し

「バッファなしチャネル」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。

チャネルとは

チャネルは、ゴルーチン間で通信するための型付きの経路です。チャネルはGoのモットーに従います: メモリを共有して通信するのではなく、通信によってメモリを共有します。

package main
import "fmt"

func main() {
    ch := make(chan int)   // unbuffered int channel

    go func() {
        ch <- 42  // send: blocks until someone receives
    }()

    v := <-ch  // receive: blocks until someone sends
    fmt.Println(v) // 42
}

バッファなしチャネルの動作

バッファなしチャネルには容量がありません。受信側の準備が整うまで送信はブロックされ、送信側が送信するまで受信はブロックされます。これにより、確実な同期的な受け渡しが実現します:

package main
import "fmt"

func double(in <-chan int, out chan<- int) {
    for v := range in {
        out <- v * 2
    }
    close(out)
}

func main() {
    in := make(chan int)
    out := make(chan int)
    go double(in, out)
    go func() { in <- 3; in <- 5; close(in) }()
    for v := range out { fmt.Println(v) }
    // 6
    // 10
}

同期におけるチャネル

バッファなしチャネルはゴルーチンを同期します。作業が完了したことを知らせるシグナルとして使用します:

package main
import "fmt"

func compute(result chan<- int) {
    sum := 0
    for i := 1; i <= 100; i++ { sum += i }
    result <- sum
}

func main() {
    ch := make(chan int)
    go compute(ch)
    fmt.Println("Result:", <-ch) // blocks until compute sends
}

チャネルを閉じる

送信側は close(ch)でチャネルを閉じ、これ以上値が送信されないことを知らせます。受信側は2値形式でクローズを検出します:

package main
import "fmt"

func generate(ch chan<- int, max int) {
    for i := 0; i < max; i++ {
        ch <- i
    }
    close(ch)  // signal done
}

func main() {
    ch := make(chan int)
    go generate(ch, 5)

    for v := range ch {  // range detects close automatically
        fmt.Println(v)
    }
    fmt.Println("channel closed")
}

2値受信

2値受信 v, ok := <-chを使うと、チャネルがまだ開いているかどうかを確認できます:

package main
import "fmt"

func main() {
    ch := make(chan string, 1)
    ch <- "hello"
    close(ch)

    v1, ok1 := <-ch
    fmt.Println(v1, ok1)  // hello true

    v2, ok2 := <-ch
    fmt.Println(v2, ok2)  // "" false — channel closed
}

クローズしたチャネルへの送信はパニックになる

クローズしたチャネルへの送信はパニックになります。チャネルを閉じるのは送信側だけにしてください。受信側は決して閉じてはいけません:

package main
import "fmt"

func main() {
    ch := make(chan int)
    close(ch)

    // Receiving from closed channel returns zero value
    v, ok := <-ch
    fmt.Println(v, ok)  // 0 false

    // Sending to closed channel panics:
    defer func() { recover() }()
    ch <- 1  // panic: send on closed channel
}

方向付きチャネル

関数シグネチャでチャネルを送信専用(chan<- T)または受信専用(<-chan T)に制限すると、意図が明確になり安全性が高まります:

package main
import "fmt"

func producer(out chan<- int) {  // send-only
    for i := 0; i < 3; i++ { out <- i }
    close(out)
}

func consumer(in <-chan int) {   // receive-only
    for v := range in { fmt.Println(v) }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

ゴルーチンとチャネルによるピンポン

2つのゴルーチンがチャネルを介してメッセージをやり取りする、典型的な同期処理の例です:

package main
import "fmt"

func ping(ping, pong chan struct{}) {
    for i := 0; i < 3; i++ {
        <-ping
        fmt.Println("ping")
        pong <- struct{}{}
    }
}

func main() {
    ping := make(chan struct{})
    pong := make(chan struct{})
    go func() { for { <-pong; fmt.Println("pong"); ping <- struct{}{} } }()
    go func() { for i := 0; i < 3; i++ { ping <- struct{}{}; <-pong } }()
    // Simplified version:
    fmt.Println("channels enable structured communication")
}

nilチャネルは永遠にブロックする

nilチャネルからの受信や nilチャネルへの送信は永遠にブロックします。これはselectステートメントで意図的に使用されることがあります:

package main
import "fmt"

func main() {
    var ch chan int  // nil channel
    fmt.Println(ch == nil) // true

    // select with nil channel — that case is never selected
    active := make(chan int, 1)
    active <- 42
    select {
    case v := <-ch:      // never selected (nil)
        fmt.Println(v)
    case v := <-active:  // selected
        fmt.Println("got:", v)
    }
}

バッファなしチャネルを使う場面

次のような場合はバッファなしチャネルを使用します:

  • 確実な同期的受け渡しが必要な場合
  • 送信側が続行する前に、ゴルーチンが受信を確認する必要がある場合
  • セマフォまたはバックプレッシャーを実装する場合
  • 各ステージが一度に1項目ずつ処理するパイプラインの場合

確認問題

受信側の準備が整っていない状態で、バッファなしチャネルに送信するとどうなりますか?

復習: バッファなしチャネル

まとめ:

  • make(chan T)で作成します — 容量は0です
  • 受信側の準備が整うまで送信はブロックされ、送信側が送信するまで受信はブロックされます
  • チャネルを閉じるのは送信側だけにしてください
  • range chはチャネルが閉じられるまで反復します
  • 2値受信: v, ok := <-ch
  • 意図を明確にするため、方向付きの型を使用します: chan<-と<-chan

よくある質問

「バッファなしチャネル」レッスンは無料ですか?

はい。「バッファなしチャネル」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。

「バッファなしチャネル」で何を学びますか?

ゴルーチン間の同期的な受け渡し ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Go Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「バッファなしチャネル」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このGo Academyレッスンでコードを書いて実行できますか?

はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ゴルーチンの起動
  2. バッファなしチャネル
  3. バッファ付きチャネル
  4. チャネルの方向とパイプラインパターン
← Go Academyに戻る