1
0

Goで並行処理を扱う

Posted at

#並行処理
アドベントカレンダー4日目は並列処理についてです。3日目はこちら

Goにおける並行処理

Goは並行処理ととても相性がよく、最大の特徴の一つといってもいいでしょう。

次に並列処理のプログラムとその実行例を見てみます。
プログラムは0から4までの数字を2倍にして表示するというものです。

package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(id int, wg *sync.WaitGroup, results chan<- int) {
	defer wg.Done()

	fmt.Printf("Worker %d starting\n", id)
	time.Sleep(time.Second)
	fmt.Printf("Worker %d done\n", id)

	results <- id * 2
}

func main() {
	const numWorkers = 5
	var wg sync.WaitGroup
	results := make(chan int, numWorkers)
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go worker(i, &wg, results)
	}

	wg.Wait()
	close(results)

	for result := range results {
		fmt.Printf("Result: %d\n", result)
	}
}

$ go run app/day4/main.go
Worker 4 starting
Worker 0 starting
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 3 done
Worker 4 done
Worker 0 done
Worker 1 done
Worker 2 done
Result: 6
Result: 8
Result: 0
Result: 2
Result: 4

もう一度実行してみます。

 go run app/day4/main.go
Worker 4 starting
Worker 2 starting
Worker 3 starting
Worker 1 starting
Worker 0 starting
Worker 1 done
Worker 0 done
Worker 4 done
Worker 3 done
Worker 2 done
Result: 2
Result: 0
Result: 8
Result: 6
Result: 4

1度目の実行と2度目の実行で値が異なっています。
Goにおける並行処理は非同期に行われ、実行順番が保証されないので注意が必要です。

実行時間を計測してみます。

$ time go run app/day4/main.go
Worker 4 starting
Worker 0 starting
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 3 done
Worker 0 done
Worker 4 done
Worker 1 done
Worker 2 done
Result: 6
Result: 0
Result: 8
Result: 2
Result: 4

real	0m1.119s
user	0m0.079s
sys	0m0.095s

time.Sleep(time.Second)を5度呼んでいるため、逐次処理ならば5秒かかるはずですが、実際は1.1秒ほどしかかかっていません。このように、待ちが発生しているようなプログラムにおいて並行処理はとても有効です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0