41
10

Go言語入門 : goroutineとチャネルを使った簡単並行処理

Last updated at Posted at 2024-06-29

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)

このプログラムを実行すると、以下のような結果が表示されます。

スクリーンショット 2024-06-29 21.15.33.png

チャネルとは

チャネルは、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)

このプログラムを実行すると、以下のような結果が表示されます。

スクリーンショット 2024-06-29 21.14.39.png

バッファ付きチャネル

バッファ付きチャネルは、メッセージを一定数ためておくことができるチャネルです。これにより、送信側が受信側の準備ができるまで待つ必要がなくなります。
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 関数は、星詠みがチャネルからメッセージを受け取る役割をします。バッファ付きチャネルを使うことで、受信が遅れても送信側が待たされることなくメッセージを送ることができます。

実行結果
このプログラムを実行すると、以下のような結果が表示されます。

スクリーンショット 2024-06-29 21.14.39.png

まとめ

go キーワードでgoroutineを簡単にスタートできる。
チャネルを使って、メッセージを安全にやり取りを行う。
バッファ付きチャネルを使うことで、送信側が受信側を待たずにメッセージを送信できる。

41
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
10