Go言語でマルチスレッド処理をする方法

Go言語でマルチスレッド処理をする方法

Go言語でマルチスレッド処理を行うためには、主に「ゴルーチン」と「チャネル」を使用します。
Go言語は、軽量なスレッドであるゴルーチンを利用して、並行処理を簡単に実現できるのが特徴です。
以下に、基本的なゴルーチンとチャネルの使い方について説明します。

ゴルーチンの利用

ゴルーチンは、Go言語で並行処理を行うための基本的な構成要素です。
ゴルーチンは、goキーワードを使って関数を非同期に実行するためのものです。
以下のコードは、ゴルーチンを使って簡単な並行処理を行う例です。

package main

import (
  "fmt"
  "time"
)

func printNumbers() {
  for i := 1; i <= 5; i++ {
    fmt.Println(i)
    time.Sleep(time.Second)
  }
}

func main() {
  go printNumbers() // ゴルーチンを起動
  time.Sleep(6 * time.Second) // メイン関数が終了する前にゴルーチンが完了するのを待つ
}

このコードでは、printNumbers関数をゴルーチンとして実行し、5秒間にわたって1から5までの数字を出力します。
time.Sleepは、ゴルーチンが終了するのを待つために使用しています。
メイン関数が早く終了しないようにするためです。

チャネルの利用

チャネルは、ゴルーチン間でデータを安全に送受信するための通信手段です。
チャネルを使うことで、複数のゴルーチンがデータを共有する際の競合状態を避けることができます。
以下は、チャネルを使ってゴルーチン間でデータをやり取りする例です。

package main

import (
  "fmt"
  "time"
)

func sendData(ch chan<- int) {
  for i := 1; i <= 5; i++ {
    ch <- i
    time.Sleep(time.Second)
  }
  close(ch) // チャネルをクローズ
}

func main() {
  ch := make(chan int) // チャネルの作成
  go sendData(ch)      // ゴルーチンを起動

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

この例では、sendData関数が整数データをチャネルに送信します。
メイン関数では、そのチャネルからデータを受信し、出力します。
チャネルがクローズされると、rangeループは終了します。

ゴルーチンとチャネルを使ったパターン

より複雑な並行処理の例として、複数のゴルーチンを起動し、それぞれからデータをチャネルを通じて受信するパターンを示します。

package main

import (
  "fmt"
  "time"
)

func worker(id int, ch chan<- string) {
  for i := 1; i <= 3; i++ {
    ch <- fmt.Sprintf("Worker %d: %d", id, i)
    time.Sleep(time.Second)
  }
}

func main() {
  ch := make(chan string)

  for i := 1; i <= 3; i++ {
    go worker(i, ch) // 複数のゴルーチンを起動
  }

  for i := 0; i < 9; i++ { // 全てのメッセージを受信
    fmt.Println(<-ch)
  }
}

この例では、3つのゴルーチンがそれぞれデータを送信します。
メイン関数では、チャネルからすべてのメッセージを受信して出力します。
ここでは、9回データを受信するループを使用しています。

Go言語では、これらの基本的な概念を利用して、効率的な並行処理を行うことができます。
ゴルーチンとチャネルをうまく活用することで、複雑な並行処理をシンプルに実装することが可能です。