📘

Go言語初学者向け!並行処理ゴルーチンとチャンネル

2025/01/20に公開

Go言語では並行処理(Concurrency)が魅力的って聞くけど上手くイメージつかない人向け(自分向け)

並行処理とは?

**並行処理(Concurrency)**は、複数の処理を同時に実行することで、アプリケーションのパフォーマンスや効率を向上させます。

例えば、ネットワーク通信を待ちながら別の計算処理を同時に行う場合などに使われます。

  • 並行処理: タスクが同時に進行しているように見える(時間を分割して交互に実行)。
  • 並列処理: 複数のプロセッサやコアを使い、タスクを物理的に同時実行。

Go言語と並行処理

Goは、言語レベルで並行処理を簡単に実現できる仕組みが組み込まれています。

ゴルーチン(goroutine)

  • Goでは「ゴルーチン」と呼ばれる軽量スレッドを使います。
  • goキーワードを使って簡単に並行処理を開始できます。
  • ゴルーチンはOSのスレッドよりも軽量で、何千個ものゴルーチンを一度に動かすことが可能です。

チャンネル(channel)

  • ゴルーチン間の通信や同期に使われる仕組み。
  • 「データを渡すパイプ」のような役割を持ち、データのやり取りを簡単に管理できます。
  • データの競合を防ぐため、チャンネルを使用します。

まずはゴルーチンを使用するかどうかの比較

ゴルーチンなしの場合

package main

import (
	"fmt"
	"time"
)

// メッセージを5回表示する関数
func say(message string) {
	for i := 0; i < 5; i++ {
		fmt.Println(message)
		time.Sleep(500 * time.Millisecond) // 0.5秒待機
	}
}

func main() {
	say("Hello") // 同期的に実行
	say("World") // Helloが終わってから実行
}

実行結果

Hello
Hello
Hello
Hello
Hello
World
World
World
World
World

  • 処理が 同期的 に進むため、say("Hello")が終わるまで次の処理に進みません。

ゴルーチンありの場合

package main

import (
	"fmt"
	"time"
)

// メッセージを5回表示する関数
func say(message string) {
	for i := 0; i < 5; i++ {
		fmt.Println(message)
		time.Sleep(500 * time.Millisecond) // 0.5秒待機
	}
}

func main() {
	go say("Hello") // ゴルーチンで並行処理
	go say("World") // ゴルーチンで並行処理

	time.Sleep(3 * time.Second) // 全ての処理が終わるのを待つ
}

実行結果


Hello
World
Hello
World
Hello
World
Hello
World
Hello
World

  • ゴルーチンを使用することで、HelloとWorldが 同時に(並行して)実行 されていることがわかります。

チャンネルを使用してゴルーチン同士でデータをやり取りする

チャンネルを使うと、ゴルーチン間で安全にデータをやり取りできます。

チャンネルを使用したコード

package main

import (
	"fmt"
)

func sendMessages(messages chan string) {
	messages <- "Hello" // チャンネルにデータを送信
	messages <- "World" // チャンネルにデータを送信
	close(messages)     // チャンネルを閉じる
}

func main() {
	messages := make(chan string) // チャンネルを作成

	go sendMessages(messages) // ゴルーチンでメッセージを送信

	for msg := range messages { // チャンネルからデータを受信
		fmt.Println(msg)
	}
}

実行結果

Hello
World

ポイント

  • messages <- "Hello": チャンネルにデータを送信。
  • <-messages: チャンネルからデータを受信。
  • close(messages): チャンネルを閉じて「もう送信するデータがない」と通知。

チャンネルを使うことで、安全にゴルーチン間のデータ通信ができます。

まとめ

  • Go言語のゴルーチンとチャンネルを使うと、並行処理を簡単に実現できます。
  • 並行処理を活用することで、アプリケーションのパフォーマンスが向上します。
  • チャンネルを使えば、ゴルーチン間のデータ通信を安全かつ簡単に行えます。

Discussion