🖥

Go言語 | goroutine 非同期処理の基本

2023/08/26に公開

内容

ループの中で、ループ回数を出力する単純なプログラムを作ってみる。

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オープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ

Twitter

https://twitter.com/YumaInaura

公開日時

2017-05-01

Discussion