0
1

More than 1 year has passed since last update.

【Golang】Goroutineまとめ

Last updated at Posted at 2022-05-12

Goroutineとは

並列処理のこと。他の言語だとマルチスレッドなどと言われる。

49 GoroutineとSync.WaitGroup

normal()とgoroutine()を並列で実行する場合、どちらかのメソッドにgoを頭につけて実行する。

package main

import (
	"fmt"
	"time"
)

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

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

func main() {
	go goroutine("world")
	normal("hello")
}
hello
world
world
hello
hello
world
world
hello
hello

ここで、timeをコメントアウトするとnormal()の実行結果しか表示されない。
スレッドを生成し、goroutine()が実行される前にnormal()が終了してしまう

package main

import (
	"fmt"
)

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

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

func main() {
	go goroutine("world")
	normal("hello")
}
hello
hello
hello
hello
hello

並列処理を実行するには以下のようにする。

package main

import (
	"fmt"
	"sync"
)

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

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

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	go goroutine("world", &wg)
	normal("hello")
	wg.Wait()
}

wgのAdd()で並列処理が一つあると宣言し、Wait()はDone()が実行されるまで終了しないという意味

50 channel

package main

import (
	"fmt"
)

func goroutine1(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum
}

func goroutine2(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum
}

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

func main() {
	s := []int{1, 2, 3, 4, 5}
	c := make(chan int)
	go goroutine1(s, c)
	go goroutine2(s, c)
	x := <-c
	fmt.Println((x))
	y := <-c
	fmt.Println((y))
}
15
15

一つのチャネルを宣言し、goroutine1()とgoroutine2()にわたす。結果をチャネルに入れて帰ってきた値を変数に入れて出力する。

51 Buffered Channel

package main

import (
	"fmt"
)

func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))
	close(ch)

	for c := range ch {
		fmt.Println(c)
	}
}

channelを作成する際、make()の第2引数に数を指定するとchannelに入れられる数を指定することができる。
指定した数を超えてchannelに値を入れようとするとエラーになる。

また、chennelからforループで取り出す際、close()を実行しておかないとエラーになる。
これは、今回の例でいうと2つの値を取り出した後3つ目を取り出そうとしてしまうため。

53 producerとconsumer

ちょっと理解度浅い
生成したproducerとconsumerの間でchをやり取りし処理を実行している

package main

import (
	"fmt"
	"sync"
)

func producer(ch chan int, i int) {
	ch <- i * 2
}

func consumer(ch chan int, wg *sync.WaitGroup) {
	for i := range ch {
		func() {
			wg.Done()
			fmt.Println("process", i*1000)
		}()
	}
	fmt.Println("##################")
}

func main() {
	var wg sync.WaitGroup
	ch := make(chan int)

	// Producer
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go producer(ch, i)
	}

	// Consumer
	go consumer(ch, &wg)
	wg.Wait()
	close(ch)
}

55 channelとselect

package main

import (
	"fmt"
	"time"
)

func goroutine1(ch chan string) {
	for {
		ch <- "packet from 1"
		time.Sleep(3 * time.Second)
	}
}

func goroutine2(ch chan int) {
	for {
		ch <- 100
		time.Sleep(1 * time.Second)
	}
}

func main() {
	c1 := make(chan string)
	c2 := make(chan int)
	go goroutine1(c1)
	go goroutine2(c2)
	for {
		select {
		case msg1 := <-c1:
			fmt.Println(msg1)
		case msg2 := <-c2:
			fmt.Println(msg2)
		}
	}
}

別々のgoroutineで処理を実行し、それらの結果によって分岐させる場合はselectを使う

56 Default selectionとfor break

package main

import (
	"fmt"
	"time"
)

func main() {
	tick := time.Tick(100 * time.Millisecond)
	boom := time.After(500 * time.Millisecond)
OuterLoop:
	for {
		select {
		case <-tick:
			fmt.Println("tick.")
		case <-boom:
			fmt.Println("BOOM")
			break OuterLoop
		default:
			fmt.Println("    .")
			time.Sleep(50 * time.Millisecond)
		}
	}
	fmt.Println("###############")
}

outerloopをforの外側に宣言し、breakの後に指定すると、breakでどのループを抜けるかを指定できる
time.Tickはchannelを返す

0
1
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
0
1