並行処理の作成
ゴルーチンは、Goにおいて並行処理を行うための軽量のスレッド。並行処理のプログラムはほかの言語ではマルチプロセスやマルチスレッド、イベント駆動とも呼ばれる。Goでは並行処理を暗黙的に実行してくれるので、ほかの言語のように深い知識がなくても並行処理を書くことができる。ゴルーチンの作り方とsync.WaitGroupを使った並行処理の制御を学ぶ。
まずは関数を二つ作成する。
func normal(s string) {
for i := 0; i<5; i++ {
time.Sleep(100 * time.Milisecond)
fmt.Println(s)
}
}
2つめを並行処理のための関数とする。(関数の内容は1つ目と同様)
func goroutine(s string) {
for i := 0; i<5; i++ {
time.Sleep(100 * time.Milisecond)
fmt.Println(s)
}
}
2つの関数をmain関数で実行する
func main() {
goroutine("world")
normal("hello")
}
//以下のように出力される
world
world
world
world
world
hello
hello
hello
hello
hello
上記のようにただ順番に関数が実行されているだけで並行処理になっていない。
並行処理にするには呼び出す関数の前に「go」をつける必要がある
func main() {
go goroutine("world")
normal("hello")
}
//以下のように出力される
hello
world
world
hello
hello
world
world
hello
hello
world
このように、goを書くだけで並行処理が実行できる。
ゴルーチンの実行前にプログラムが終了する場合
「time.Sleep(100 * time.Milisecond)」をコメントアウトして実行すると「hello」のみが出力されて処理が終了してしまう。
func normal(s string) {
for i := 0; i<5; i++ {
// time.Sleep(100 * time.Milisecond)
fmt.Println(s)
}
}
func goroutine(s string) {
for i := 0; i<5; i++ {
// time.Sleep(100 * time.Milisecond)
fmt.Println(s)
}
}
func main() {
go goroutine("world")
normal("hello")
}
//以下のように出力される
hello
hello
hello
hello
hello
これは、「go goroutine("world")」で生成された並行処理のスレッドが実行される前にnormal関数の処理が終わってしまったため。そのため、goroutine関数で「world」を表示する前にコードが終了してしまった。ゴルーチンの処理が終わらなくてもプログラムが終了してしまう、ということを覚えておく必要がある。
sync.WaitGroupで並行処理を待機させる
プログラムが途中で終了することを避けるには、syncWaitGroupを使う。main関数で「var wg sync.WaitGroup」(Go言語における並行処理を管理するための構造体を宣言するコード)と宣言し、「wg.Add(1)」(sync.WaitGroup構造体が持つAddメソッドを利用)と書いて並行処理が1つあることを伝える。
次に、goroutine関数の引数に「wg *sync.WaitGroup」と書いて、wgのアドレスを渡す。また、goroutine関数の最後に、「wg.Done()」と書く。
最後に、main関数内に「wg.Wait()」を書くと、「wg.Done()」が実行されるまで待機する。実行するとtime.Sleepをしなくても「hello」と「world」がすべて表示される。
import (
"fmt"
"sync"
)
func normal(s string) {
for i := 0; i<5; i++ {
fmt.Println(s)
}
}
func goroutine(s string, wg *sync.WaitGroup) {
defer wg.Done() //処理が終わったらwg.Doneされるようにdeferで先に書いておく
for i := 0; i<5; i++ {
fmt.Println(s)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(1) //並行処理が一つあることを伝える
go gorutine("world", &wg)
normal("hello")
wg.Wait() //wg.Doneが処理されるまで待つ。
}
//以下のように出力される
hello
world
world
hello
hello
world
world
hello
hello
world
学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP
・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897