goの概要
並行処理(ゴルーチン) Goの予約語 | ||
go 概要 |
||
|
基本的なgoの使い方
go
キーワードを使うと、関数を新しいゴルーチンで実行できます。
package main
import (
"fmt"
"time"
)
// ゴルーチンとして実行する関数
func hello() {
fmt.Println("Hello, Goroutine!")
}
func main() {
go hello() // 新しいゴルーチンを開始
time.Sleep(time.Second) // メインゴルーチンが終了しないように待機
}
解説:
go hello()
で、hello
関数を新しいゴルーチンとして実行します。- ゴルーチンはメインゴルーチンとは独立して動作するため、メインゴルーチンが先に終了すると
hello()
が実行されない可能性があります。 - そのため、
time.Sleep(time.Second)
を入れて、メインゴルーチンが終了する前にhello()
が実行されるようにしています。
実行結果:
Hello, Goroutine!
複数のゴルーチンを実行
複数のゴルーチンを作成すると、それぞれが並行して実行されます。
package main
import (
"fmt"
"time"
)
func printNumber(num int) {
fmt.Println("Number:", num)
}
func main() {
for i := 1; i <= 5; i++ {
go printNumber(i) // 5つのゴルーチンを作成
}
time.Sleep(time.Second) // 全てのゴルーチンの実行を待つ
}
解説:
go printNumber(i)
を5回実行することで、5つのゴルーチンが並行実行されます。- 出力の順番は保証されません(ゴルーチンの実行タイミングによる)。
- メインゴルーチンが終了すると、未完了のゴルーチンも強制終了されるため、
time.Sleep(time.Second)
を入れて待機します。
実行結果(順不同):
Number: 3 Number: 1 Number: 5 Number: 2 Number: 4
sync.WaitGroupを使ったゴルーチンの終了待ち
sync.WaitGroup
を使うと、すべてのゴルーチンの終了を確実に待つことができます。
package main
import (
"fmt"
"sync"
)
func printMessage(msg string, wg *sync.WaitGroup) {
defer wg.Done() // 処理終了時にカウンタを減らす
fmt.Println(msg)
}
func main() {
var wg sync.WaitGroup
messages := []string{"Go", "is", "awesome!"}
for _, msg := range messages {
wg.Add(1) // カウンタを増やす
go printMessage(msg, &wg)
}
wg.Wait() // すべてのゴルーチンの終了を待つ
}
解説:
sync.WaitGroup
を使用し、ゴルーチンの終了を管理します。- ゴルーチンを起動するたびに
wg.Add(1)
でカウンタを増やし、終了時にwg.Done()
で減らします。 wg.Wait()
を使うことで、すべてのゴルーチンが終了するまでmain
関数が終了しないようにします。
実行結果(順不同):
is Go awesome!
チャネルを使ったゴルーチン間の通信
チャネルを使うと、ゴルーチン間で安全にデータをやり取りできます。
package main
import (
"fmt"
)
func sendMessage(ch chan string) {
ch <- "Hello from Goroutine!"
}
func main() {
ch := make(chan string)
go sendMessage(ch)
msg := <-ch // ゴルーチンからのメッセージを受信
fmt.Println(msg)
}
解説:
ch := make(chan string)
でチャネルを作成し、ゴルーチン間の通信を可能にします。sendMessage
関数がゴルーチン内でch
にデータを送信し、main
関数で受信します。
実行結果:
Hello from Goroutine!
注意事項
- ゴルーチンの終了を待たないとプログラムがすぐ終了する:
sync.WaitGroup
やチャネルを使って制御する。 - ゴルーチンの順番は保証されない: 実行順序はランダム。
- データ競合に注意: 共有データへのアクセスには
sync.Mutex
やチャネルを使う。
よくある質問
- Q: ゴルーチンはスレッドとは違うのですか?
- A: はい。ゴルーチンはOSのスレッドよりも軽量で、Goランタイムによって効率的にスケジューリングされます。
- Q: すべての関数をgoで並行実行できますか?
- A: 可能ですが、すべてを並行実行すると制御が難しくなるため、適切に設計する必要があります。
- Q: ゴルーチンを確実に終了させる方法は?
- A:
sync.WaitGroup
やチャネルを使ってゴルーチンの終了を待つのが一般的です。
まとめ
go
を使うとゴルーチンを作成し、関数を並行実行できる。- メインゴルーチンの終了を待つために、
sync.WaitGroup
やtime.Sleep
を使う。 - チャネルを活用すると、ゴルーチン間の安全な通信が可能。