Go 入門

Go言語入門⑭ ~goroutine・channel・Buffered Channels~

タイトル:Go言語入門⑭ ~goroutine・channel・Buffered Channels~
[box class="blue_box" title="☑本記事の内容"]

  • goroutine
  • channel
  • Buffered Channels

[/box]
参考資料:現役シリコンバレーエンジニアが教えるGo入門 + 応用でビットコインのシストレFintechアプリの開発
[box class="glay_box" title="Contents"]

  1. Go言語入門-goroutine-
  2. Go言語入門-channel-
  3. Go言語入門-Buffered Channels-

[/box]

Go言語入門-goroutine-

[box class="yellow_box" title="✔goroutineの目次"]

[/box]

基本的なこと

[box class="glay_box"]

  • 並列化の事
  • 関数を同時に実行する
  • 下記のコードだと順番に実行される

[/box]

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() {
	goroutine("world")
	normal("hello")

}
(結果)
world
world
world
world
world
hello
hello
hello
hello
hello

[box class="glay_box"]

  • goを追加することで並列処理になる

[/box]

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")
}
(結果)
world
hello
hello
world
hello
world
world
hello
hello

並列処理されない場合

[box class="glay_box"]

  • time.Sleep(100 * time.Millisecond)を消すと並列処理がされない
  • gorutineが実行される前に処理が終了してしまうため

[/box]

package main

import (
	"fmt"
)

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

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

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

実行されない場合を回避する方法

[box class="glay_box"]

  • sync.WaitGroupを使用する
  • Wait(),Add(),Done()を使用することで並列処理が実行されるまで待つ
  • Done()だけ忘れていたりするとエラーとなるので注意

[/box]

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()
}
(結果)
hello
hello
hello
hello
hello
world
world
world
world
world

Go言語入門-channel-

[box class="yellow_box" title="✔channelの目次"]

[/box]

基本的なこと

[box class="glay_box"]

  • goroutineを使用する場合は並列に処理が走っているのでデータのやりとりが出来ない
  • それを解消するためにchannelを使用する
  • channelは並列している処理が完了するまで待つ

[/box]

package main

import "fmt"

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

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

Go言語入門-Buffered Channels-

[box class="yellow_box" title="✔Buffered Channelsの目次"]

[/box]

基本的なこと

[box class="glay_box"]

  • 作成したchannelにはどんどん値を追加出来る
  • 最初に指定した数字よりも多い個数値を入れようとするとエラーになる

[/box]

package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))
}
(結果)
1
2
package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))
	ch <- 300
	fmt.Println(len(ch))
}
(結果)エラー表示
1
2
fatal error: all goroutines are asleep - deadlock!

[box class="glay_box"]

  • channelを取り出すと再度channelに入れることが出来る

[/box]

package main

import "fmt"

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

	x := <-ch
	fmt.Println(x)

	ch <- 300
	fmt.Println(len(ch))
}
(結果)
1
2
100
2

rangeで取り出す場合

[box class="glay_box"]

  • rangeを使用して値を取り出すことも出来る
  • rangeを使用する場合はchannelを一度closeする必要がある

[/box]

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)
	}
}
(結果)
1
2
100
200

Go言語入門⑮へ ≫

≪ Go言語入門⑬へ

目次

-Go, 入門