Go言語の特徴の一つに、軽量な並行処理を簡単に実現できる「goroutine」と「チャネル」があります。本記事では、goroutineとチャネルの基本概念とその使い方について、学んだことをアウトプットしたいと思います。
goroutineとは
goroutineは、Go言語で使われる軽量なスレッドのようなもので、並行処理を簡単に実現するための機能です。goroutineを使うと、複数の処理を同時に実行することができます。
goroutineの基本概念
軽量な並行処理: goroutineは少ないメモリで多くの仕事を同時にこなせます。
簡単な使い方: 関数呼び出しの前にgo
キーワードを使うだけで、簡単にgoroutineをスタートできます。
go 関数名()
実例1: 基本的なgoroutine
以下は、goroutineを使ってメッセージを表示する簡単な例です。
※ 原神でお馴染みのナヴィアさんのセリフを例にしています。
package main
import (
"fmt"
"time"
)
func say(message string) {
for i := 0; i < 2; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(message)
}
}
func main() {
go say("ローズクラッカー! 「棘薔薇の会」特注版よ。") // ゴルーチンで「ローズクラッカー! 「棘薔薇の会」特注版よ。」と表示
say("ファイアー! ま、岩元素なんだけどね。") // メインの関数で「ファイアー!ま、岩元素なんだけどね。」と表示
}
実行結果(The Go Playground)
このプログラムを実行すると、以下のような結果が表示されます。
チャネルとは
チャネルは、goroutine同士がメッセージをやり取りするためのものです。これを使うと、安全に情報を交換できます。
実例2: チャネルでメッセージを送受信
次に、VTuberの星街すいせいさんが星詠みにメッセージを送り、星詠みがそのメッセージを受け取る例を見てみましょう。
package main
import (
"fmt"
"time"
)
// メッセージを送る関数
func sendMessage(messages chan string) {
messages <- "彗星のごとく現れたスターの原石!アイドルVTuberの星街すいせいです!!" // メッセージを送る
time.Sleep(time.Second)
messages <- "すいちゃんは~?" // もう一つメッセージを送る
time.Sleep(time.Second)
messages <- "今日もかわいいー!" // さらにもう一つメッセージを送る
}
// 星詠みがメッセージを受け取る関数
func receiveMessage(messages chan string) {
msg := <-messages // メッセージを受け取る
fmt.Println("星詠み:", msg)
msg = <-messages // 次のメッセージを受け取る
fmt.Println("星詠み:", msg)
msg = <-messages // 次のメッセージを受け取る
fmt.Println("星詠み:", msg)
}
func main() {
messages := make(chan string) // メッセージのやり取りをするチャネルを作成
go sendMessage(messages) // 星街すいせいgoroutineをスタート
go receiveMessage(messages) // 星詠みgoroutineをスタート
// goroutineが終わるのを少し待つ
time.Sleep(3 * time.Second)
}
実行結果(The Go Playground)
このプログラムを実行すると、以下のような結果が表示されます。
バッファ付きチャネル
バッファ付きチャネルは、メッセージを一定数ためておくことができるチャネルです。これにより、送信側が受信側の準備ができるまで待つ必要がなくなります。
makeを使ってチャネルを作成して、バッファのサイズを第2引数に渡すことで定義できます。
ch := make(chan int, 3)
実例3: バッファ付きチャネルでメッセージを送受信
次に、バッファ付きチャネルを使った例を見てみましょう。
package main
import (
"fmt"
"time"
)
// メッセージを送る関数
func sendMessage(messages chan string) {
messages <- "彗星のごとく現れたスターの原石!アイドルVTuberの星街すいせいです!!" // メッセージを送る
time.Sleep(time.Second)
messages <- "すいちゃんは~?" // もう一つメッセージを送る
time.Sleep(time.Second)
messages <- "今日もかわいいー!" // さらにもう一つメッセージを送る
}
// 星詠みがメッセージを受け取る関数
func receiveMessage(messages chan string) {
for i := 0; i < 3; i++ {
msg := <-messages // メッセージを受け取る
fmt.Println("星詠み:", msg)
}
}
func main() {
messages := make(chan string, 3) // バッファ付きチャネルを作成
go sendMessage(messages) // 星街すいせいgoroutineをスタート
go receiveMessage(messages) // 星詠みgoroutineをスタート
// goroutineが終わるのを少し待つ
time.Sleep(3 * time.Second)
}
プログラムの説明
バッファ付きチャネルの作成: messages := make(chan string, 3) というように、バッファサイズを指定してチャネルを作成します。
メッセージの送信: sendMessage 関数は、星街すいせいさんがメッセージをチャネルに送る役割をします。
メッセージの受信: receiveMessage 関数は、星詠みがチャネルからメッセージを受け取る役割をします。バッファ付きチャネルを使うことで、受信が遅れても送信側が待たされることなくメッセージを送ることができます。
実行結果
このプログラムを実行すると、以下のような結果が表示されます。
まとめ
go キーワードでgoroutineを簡単にスタートできる。
チャネルを使って、メッセージを安全にやり取りを行う。
バッファ付きチャネルを使うことで、送信側が受信側を待たずにメッセージを送信できる。