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を使う。 - チャネルを活用すると、ゴルーチン間の安全な通信が可能。