🖥
Go言語 | goroutine 非同期処理の基本
内容
ループの中で、ループ回数を出力する単純なプログラムを作ってみる。
go func を書く
for i := 1; i < 100; i++ {
go func() {
fmt.Println(i)
}()
}
結果
出力される行数を数えると、100個に満たない。
非同期処理が終わる前にプログラムが終わってしまっている。
$ go run script.go | wc -l
93
非同期処理が終わるまで待つ
for i := 1; i <= 100; i++ {
go func() {
fmt.Println(i)
}()
}
+ time.Sleep(10000000)
結果
ちゃんと100行出力されるようになった。
$ go run script.go with_sleep | wc -l
100
だが中身を見てみると、重複する値がいくつも出力されている。
$ go run script.go
7
30
13
37
14
45
45
46
46
46
46
..
function に引数を渡す
for i := 1; i <= 100; i++ {
- go func(i int) {
+ go func() {
fmt.Println(i)
- }(i)
+ }()
}
time.Sleep(10000000)
結果
これで重複する値が排除された。
$ go run goroutine/basis/main.go
3
1
2
19
11
12
13
..
Sleep から Wait へ
sync パッケージを使うことで、Sleepで秒数を明示したりしなくても、非同期処理が終わるまで待ってくれるようになる。
+ var wg sync.WaitGroup
for i := 1; i <= 100; i++ {
+ wg.Add(1) // Wait用のカウンタをインクリメント
go func(i int) {
+ defer wg.Done() // Wait用のカウンタをデクリメント
fmt.Println(i)
}(i)
}
+ wg.Wait()
結果
ひとつ前と同じ。
検証コード
package main
import (
"fmt"
"os"
"sync"
"time"
)
func main() {
if os.Args[1] == "without_sleep" {
without_sleep()
} else if os.Args[1] == "with_sleep" {
with_sleep()
} else if os.Args[1] == "with_argument" {
with_argument()
} else if os.Args[1] == "with_wait" {
with_wait()
}
}
func without_sleep() {
for i := 1; i < 101; i++ {
go func() {
fmt.Println(i)
}()
}
}
func with_sleep() {
for i := 1; i < 101; i++ {
go func() {
fmt.Println(i)
}()
}
time.Sleep(10000000)
}
func with_argument() {
for i := 1; i < 101; i++ {
go func(i int) {
fmt.Println(i)
}(i)
}
time.Sleep(10000000)
}
func with_wait() {
var wg sync.WaitGroup
for i := 1; i < 101; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(i)
}(i)
}
wg.Wait()
}
環境
- go version go1.8.1 darwin/amd64
参考
チャットメンバー募集
何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。
公開日時
2017-05-01
Discussion