Go言語のバッファ付きchannelと非バッファchannelの違いを徹底解説!初心者でもわかる並行処理の基本
生徒
「先生!Go言語のチャンネルには“バッファ付き”と“非バッファ”があると聞いたのですが、何が違うんですか?」
先生
「とても良い質問ですね。Go言語(Golang)では、並行処理(コンカレンシー)を行うときにchannel(チャンネル)を使います。その中でも“バッファ付き”と“非バッファ”では動作の仕方が大きく異なるんですよ。」
生徒
「なるほど…でも、具体的にどんな違いがあるんですか?」
先生
「それでは、Go言語のバッファ付きchannelと非バッファchannelの違いを、初心者にも分かりやすく例えやサンプルコードを使って説明していきましょう。」
1. Go言語のchannel(チャンネル)とは?
Go言語のchannel(チャンネル)は、goroutine(ゴルーチン)同士でデータを受け渡しするための通路です。ゴルーチンとは、Go言語が持つ軽量な並行処理の仕組みのことです。
チャンネルを使うと、複数の処理が同時に動いていても、安全にデータをやり取りすることができます。まるで「宅配ボックス」のような役割を果たします。送り手(生産者)がデータを入れて、受け手(消費者)が取り出すという仕組みです。
2. 非バッファchannelとは?
非バッファチャンネルとは、データの一時的な保管場所がないチャンネルのことです。つまり、送信側と受信側が「同時に」動作しないとデータが送れません。
イメージとしては「手渡しのリレー」です。送り手がボールを持ったまま待っていて、受け取る人が来た瞬間に渡す、という感じです。
package main
import "fmt"
func main() {
ch := make(chan string) // 非バッファchannelを作成
go func() {
ch <- "こんにちは"
}()
msg := <-ch
fmt.Println(msg)
}
この例では、ch := make(chan string)で非バッファチャンネルを作成しています。ゴルーチンがメッセージを送信し、メイン関数がそれを受け取るまで送信側はブロック(停止)されます。
こんにちは
このように、非バッファチャンネルは「相手が準備できるまで待つ」ため、通信のタイミングを厳密にコントロールできます。
3. バッファ付きchannelとは?
次に、バッファ付きチャンネルについて説明します。バッファとは「一時的にデータをためておく箱」のようなものです。Go言語では、チャンネルを作るときにバッファのサイズを指定できます。
package main
import "fmt"
func main() {
ch := make(chan string, 2) // バッファサイズ2のchannel
ch <- "りんご"
ch <- "みかん"
fmt.Println(<-ch)
fmt.Println(<-ch)
}
この例では、バッファサイズが「2」なので、受信側がいなくても2つまでデータを送信できます。たとえるなら「2つまで入る宅配ボックス」です。
りんご
みかん
ただし、3つ目を送ろうとすると、ボックスがいっぱいになり、誰かが1つ取り出すまで送信側は待つことになります。
4. バッファ付きと非バッファ付きの違いを図解でイメージ
違いをシンプルにまとめると次のようになります。
- 非バッファchannel: データの受け渡しはリアルタイム。送信と受信が同時でないと進まない。
- バッファ付きchannel: 一定数のデータを一時的に溜められる。送信が受信を待たずに進む場合もある。
これを生活に例えると、
- 非バッファ: 手渡しで直接荷物を渡す(相手がその場にいないと渡せない)
- バッファ付き: 宅配ボックスに荷物を入れておける(あとで相手が受け取る)
5. バッファ付きchannelの挙動を実験してみよう
もう少し動きを具体的に見てみましょう。以下のコードでは、バッファサイズを「1」にして、送信と受信のタイミングを観察します。
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string, 1)
go func() {
ch <- "A"
fmt.Println("1つ目送信完了")
ch <- "B"
fmt.Println("2つ目送信完了")
}()
time.Sleep(2 * time.Second)
fmt.Println("受信:", <-ch)
fmt.Println("受信:", <-ch)
}
1つ目送信完了
受信: A
2つ目送信完了
受信: B
この結果を見ると、最初の「A」はすぐに送れますが、「B」を送るときはバッファがいっぱいになるため、一時的に停止します。そして受信側が「A」を取り出した後に「B」が送信されるのです。
6. どちらを使えばいいのか?
非バッファチャンネルは、送信と受信のタイミングを厳密に合わせたい場合に使われます。例えば、複数のゴルーチンの同期をとる場面などです。
一方で、バッファ付きチャンネルは、処理の流れを緩やかにしたいときや、一時的にデータをためて非同期に動かしたいときに便利です。例えば、ログをためて処理するようなシステムや、キュー(待ち行列)のような仕組みで使うことが多いです。