カテゴリ: Go言語 更新日: 2025/12/17

Go言語のバッファ付きchannelと非バッファchannelの違いを徹底解説!初心者でもわかる並行処理の基本

Go言語のバッファ付きchannelと非バッファchannelの違い
Go言語のバッファ付きchannelと非バッファchannelの違い

先生と生徒の会話形式で理解しよう

生徒

「先生!Go言語のチャンネルには“バッファ付き”と“非バッファ”があると聞いたのですが、何が違うんですか?」

先生

「とても良い質問ですね。Go言語(Golang)では、並行処理(コンカレンシー)を行うときにchannel(チャンネル)を使います。その中でも“バッファ付き”と“非バッファ”では動作の仕方が大きく異なるんですよ。」

生徒

「なるほど…でも、具体的にどんな違いがあるんですか?」

先生

「それでは、Go言語のバッファ付きchannelと非バッファchannelの違いを、初心者にも分かりやすく例えやサンプルコードを使って説明していきましょう。」

1. Go言語のchannel(チャンネル)とは?

1. Go言語のchannel(チャンネル)とは?
1. Go言語のchannel(チャンネル)とは?

Go言語のchannel(チャンネル)は、goroutine(ゴルーチン)同士でデータを受け渡しするための通路です。ゴルーチンとは、Go言語が持つ軽量な並行処理の仕組みのことです。

チャンネルを使うと、複数の処理が同時に動いていても、安全にデータをやり取りすることができます。まるで「宅配ボックス」のような役割を果たします。送り手(生産者)がデータを入れて、受け手(消費者)が取り出すという仕組みです。

2. 非バッファchannelとは?

2. 非バッファchannelとは?
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とは?

3. バッファ付きchannelとは?
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. バッファ付きと非バッファ付きの違いを図解でイメージ

4. バッファ付きと非バッファ付きの違いを図解でイメージ
4. バッファ付きと非バッファ付きの違いを図解でイメージ

違いをシンプルにまとめると次のようになります。

  • 非バッファchannel: データの受け渡しはリアルタイム。送信と受信が同時でないと進まない。
  • バッファ付きchannel: 一定数のデータを一時的に溜められる。送信が受信を待たずに進む場合もある。

これを生活に例えると、

  • 非バッファ: 手渡しで直接荷物を渡す(相手がその場にいないと渡せない)
  • バッファ付き: 宅配ボックスに荷物を入れておける(あとで相手が受け取る)

5. バッファ付きchannelの挙動を実験してみよう

5. バッファ付き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. どちらを使えばいいのか?

6. どちらを使えばいいのか?
6. どちらを使えばいいのか?

非バッファチャンネルは、送信と受信のタイミングを厳密に合わせたい場合に使われます。例えば、複数のゴルーチンの同期をとる場面などです。

一方で、バッファ付きチャンネルは、処理の流れを緩やかにしたいときや、一時的にデータをためて非同期に動かしたいときに便利です。例えば、ログをためて処理するようなシステムや、キュー(待ち行列)のような仕組みで使うことが多いです。

カテゴリの一覧へ
新着記事
New1
Go言語
Go言語のオブジェクト指向の特徴を完全ガイド!初心者でも理解できる他言語との違い
New2
Go言語
Go言語の条件分岐の見やすい書き方を徹底解説!初心者でもわかるif文の使い方
New3
Kotlin
Kotlinのクラス設計に役立つベストプラクティスまとめ|初心者でもわかるクラス設計の考え方
New4
Kotlin
Kotlinでアーキテクチャ設計の基本!MVC・MVP・MVVMの違いを解説
人気記事
No.1
Java&Spring記事人気No1
Go言語
Go言語の関数パラメータ!値渡しと参照渡しの違いを理解しよう
No.2
Java&Spring記事人気No2
Swift
Swift Playgroundの使い方を完全解説!初心者に最適な学習環境の始め方
No.3
Java&Spring記事人気No3
Swift
Swift開発環境の構築方法を徹底解説!Xcode・Windows・Linux対応
No.4
Java&Spring記事人気No4
Kotlin
Gradleファイル(build.gradle.kts)の書き方と役割をやさしく解説!Kotlin初心者向け完全ガイド
No.5
Java&Spring記事人気No5
Kotlin
Kotlinのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.6
Java&Spring記事人気No6
Go言語
Go言語のWebアプリにおけるセキュリティベストプラクティス集
No.7
Java&Spring記事人気No7
Kotlin
Kotlinの演算子一覧と使い方!算術・比較・論理演算子の基本を解説
No.8
Java&Spring記事人気No8
Swift
Swiftのオプショナル型とは?初心者でもわかる使い方とアンラップの基礎