タイトル:Go言語入門⑭ ~goroutine・channel・Buffered Channels~
[box class="blue_box" title="☑本記事の内容"]
- goroutine
- channel
- Buffered Channels
[/box]
参考資料:現役シリコンバレーエンジニアが教えるGo入門 + 応用でビットコインのシストレFintechアプリの開発
[box class="glay_box" title="Contents"]
[/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