Go言語で並列処理をする方法

Go言語で並列処理をする方法

Go言語での並列処理は、主に「goroutine」と「channel」という2つの主要な機能を使って実現します。
これにより、効率的にタスクを並行して実行し、パフォーマンスを向上させることが可能です。

1. goroutine

Go言語では、goroutineを使用して軽量なスレッドを作成します。
goroutineは、並行して実行される関数やメソッドの呼び出しを提供します。
goroutineは、goキーワードを関数呼び出しの前に付けることで作成できます。

package main

import (
  "fmt"
  "time"
)

func sayHello() {
  for i := 0; i < 5; i++ {
    fmt.Println("Hello")
    time.Sleep(time.Second)
  }
}

func main() {
  go sayHello() // sayHello関数をgoroutineとして実行
  time.Sleep(6 * time.Second) // メインゴルーチンが終了する前に待機
}

この例では、sayHello関数がgoroutineとして実行され、メインのゴルーチンと並行して動作します。
time.Sleepを使ってメインのゴルーチンが終了する前に待機しています。

2. channel

channelは、goroutine間でデータを通信するための同期手段です。
channelを使うことで、goroutine間でデータを安全に受け渡しできます。
channelは、make関数を使って作成します。

package main

import (
  "fmt"
)

func sendData(ch chan<- int) {
  for i := 0; i < 5; i++ {
    ch <- i // チャネルにデータを送信
  }
  close(ch) // チャネルをクローズ
}

func receiveData(ch <-chan int) {
  for data := range ch {
    fmt.Println(data) // チャネルからデータを受信
  }
}

func main() {
  ch := make(chan int) // チャネルを作成
  go sendData(ch) // データ送信用のgoroutine
  receiveData(ch) // メインゴルーチンでデータ受信
}

この例では、sendData関数がデータをchannelを通じて送信し、receiveData関数がそれを受信します。
channelを通じてデータの送受信を行うことで、データの整合性を保ちながら並列処理を実現します。

3. Select文

select文を使用すると、複数のchannelからの送受信を待機し、どのchannelが最初に準備できるかに応じて処理を行います。
select文は、複数のchannelを扱う場合に非常に便利です。

package main

import (
  "fmt"
  "time"
)

func main() {
  ch1 := make(chan string)
  ch2 := make(chan string)

  go func() {
    time.Sleep(2 * time.Second)
    ch1 <- "Message from ch1"
  }()

  go func() {
    time.Sleep(1 * time.Second)
    ch2 <- "Message from ch2"
  }()

  select {
  case msg1 := <-ch1:
    fmt.Println(msg1)
  case msg2 := <-ch2:
    fmt.Println(msg2)
  }
}

この例では、ch1とch2の2つのchannelからのメッセージをselect文を使って待機し、どちらかのchannelからメッセージが受信されると、それを処理します。
select文は、複数のchannel操作を同時に管理する際に役立ちます。

4. WaitGroup

sync.WaitGroupを使うことで、複数のgoroutineの終了を待機することができます。
WaitGroupは、Add、Done、Waitの3つのメソッドを持ちます。

package main

import (
  "fmt"
  "sync"
)

func worker(wg *sync.WaitGroup, id int) {
  defer wg.Done() // 作業が終了したらDoneを呼び出す
  fmt.Printf("Worker %d started\n", id)
}

func main() {
  var wg sync.WaitGroup

  for i := 1; i <= 3; i++ {
    wg.Add(1) // WaitGroupに1つのgoroutineを追加
    go worker(&wg, i)
  }

  wg.Wait() // すべてのgoroutineの終了を待機
  fmt.Println("All workers completed")
}

この例では、worker関数を3つのgoroutineで並行して実行し、WaitGroupを使ってすべてのworkerが終了するまでメインゴルーチンが待機します。
WaitGroupは、並行処理の終了管理に非常に有用です。

Go言語の並列処理は、これらの機能を組み合わせることで、シンプルで強力な並行プログラムを構築することができます。
goroutineを使って並行処理を実行し、channelでデータの送受信を行い、selectやWaitGroupで処理の管理をすることで、効率的なプログラムを作成できます。