はじめに
Go言語の特徴の一つに「並行処理の簡潔さ」が挙げられます。本記事では、Goの並行処理について基礎から学び、実際に役立つサンプルコードを解説していきます。
並行処理とは?
並行処理(Concurrency)は、複数のタスクを同時に進行させる技術です。Goでは、goroutine と呼ばれる軽量スレッドを用いて並行処理を実現します。
例えば、以下のようなシナリオがあるとします:
- Webサーバーが同時に複数のクライアントリクエストを処理する。
- 大量のデータを並行して処理して、高速化を図る。
こうした処理を簡潔に実現できるのが、Goのgoroutineとチャネル(channel)です。
基本:goroutineの使い方
Goでgoroutineを使うのは非常に簡単です。go
キーワードを使うだけで関数を並行実行できます。
コード例
package main
import (
"fmt"
"time"
)
func sayHello() {
for i := 0; i < 5; i++ {
fmt.Println("Hello, World!")
time.Sleep(500 * time.Millisecond)
}
}
func main() {
go sayHello() // goroutineで実行
for i := 0; i < 5; i++ {
fmt.Println("Main Function")
time.Sleep(300 * time.Millisecond)
}
}
この例では、sayHello
関数がgoroutineとして並行実行され、メイン関数の処理と同時に動作します。
実践:チャネル(channel)の活用
goroutine間でデータをやり取りするには、チャネル(channel)が便利です。
チャネルの基礎
チャネルはデータを送受信するための仕組みで、make(chan 型)
で生成します。
package main
import "fmt"
func sendData(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i // データを送信
}
close(ch) // チャネルを閉じる
}
func main() {
ch := make(chan int) // チャネルを作成
go sendData(ch) // goroutineでデータを送信
for data := range ch { // チャネルからデータを受信
fmt.Println(data)
}
}
このコードでは、sendData
関数がチャネルを通じてデータを送信し、main
関数がそれを受け取ります。
よくある課題と解決策
1. デッドロック(Deadlock)
チャネルを正しく管理しないと、デッドロックが発生することがあります。デッドロックは、goroutineが互いに待機し続ける状態です。
解決策
- チャネルを必ず閉じる。
- バッファ付きチャネルを利用する。
ch := make(chan int, 2) // バッファサイズを指定
ch <- 1
ch <- 2
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
応用:ワーカー(Worker)パターン
並行処理で効率よくタスクを処理するには、ワーカーパターンが有用です。以下にタスクをワーカーに分散させる例を示します。
package main
import (
"fmt"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("Worker %d started job %d\n", id, job)
time.Sleep(time.Second) // ジョブ処理に1秒
fmt.Printf("Worker %d finished job %d\n", id, job)
results <- job * 2
}
}
func main() {
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
// ワーカーを3つ作成
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// ジョブを送信
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// 結果を受信
for a := 1; a <= numJobs; a++ {
fmt.Println("Result:", <-results)
}
}
まとめ
Go言語の並行処理は、goroutine
とchannel
を用いることで、簡潔かつ強力に実現できます。本記事で紹介した基礎を押さえることで、実用的な並行処理プログラムを構築できるようになります。