1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ゴールーチンのメモ(チャネルなど)

Posted at

Goroutineとは

Goroutineとは、goのステートメントで、関数を指定することによって並行実行されるもの。

package main

import (
	"fmt"
	"time"
)

func main() {
	go goroutine("Hello!")
	hoge("World!")
}

func goroutine(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func hoge(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

> World!
> Hello!
> Hello!
> World!
> World!
> Hello!
> Hello!
> World!
> Hello!
> World!
 並行で実行したため表示される順番がバラバラ

sync.WaitGroup

Goroutineに指定した関数は、メインスレッド(main関数)が終了してしまうと、実行されずに終わってしまう。
こうなると、並行で実行して欲しいのものができなくなってしまう。
上のコードだと、各関数のtime.Sleep()をコメントアウトして実行すると、Worldが5回表示されて終了する。

これを防ぐためにsync.WaitGroupがある。

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	go goroutine("Hello!", &wg)
	hoge("World!")
	wg.Wait()
}

func goroutine(s string, wg *sync.WaitGroup) {
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
	wg.Done()
}

func hoge(s string) {
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
}

このように、wgという変数を宣言して、wg.Add(1)とすることで、1個の並行処理が実行されることを示す。また、wgをgoroutineで指定する関数の引数に渡す。
wg.Wait()を書くことでwg.Done()が呼ばれるまで待ってくれる。この場合は、func goroutine()wg.Done()を書いて、main関数にwg.Wait()を書いたので、main関数はfunc goroutine()が終わるまで待ってくれた。
wg.Add()でwgをインクリメント、wg.Done()でwgをデクリメントして、wg.Wait()でwgのカウンタが0になるまで待つ、という感じ。なので、wg.Add()が書かれていなかったりwg.Done()が書かれていないと、エラーになる。

また、goroutine関数内でのwg.Done()の呼び方として、

func goroutine(s string, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
}

という呼び方もできる。こっちの方が、wg.Done()を書き忘れなさそうな気がする。

チャネル

複数のgoroutine間でデータのやり取りを行うために、チャネルというものがある。

package main

import "fmt"

func sum(s []int, ch chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	// チャネルにデータを送信
	ch <- sum
}

func main() {
	// チャネルの作成
	ch := make(chan int)

	s := []int{1, 1, 1}
	go sum(s, ch)

	// チャネルからデータを受信
	sum := <-ch
	fmt.Println(sum)
}

sum := <-chでブロッキングされるので、sync.WaitGroup()で待機する必要はない。
上のコードだと、func sum()のスレッドからmain関数のスレッドにsumの値が渡される

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?