Go 入門

Go言語入門⑯ ~changeとselect・Default Selection・sync.Mutex~

[box class="blue_box" title="☑本記事の内容"]

  • changeとselect
  • Default Selection
  • sync.Mutex

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

  1. Go言語入門-changeとselect-
  2. Go言語入門-Default Selection-
  3. Go言語入門-sync.Mutex-

[/box]

Go言語入門-changeとselect-

[box class="glay_box"]

  • channelを複数使用する時に利用
  • お互いのchannelは干渉しない
  • 異なる型でも実行可能

[/box]

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)
		}
	}
}
(結果)
100
packet from 1
100
100
packet from 1
100
100
100
packet from 1

Go言語入門-changeとselect-

処理参考図

Go言語入門-Default Selection-

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

[/box]

基本的なこと

[box class="glay_box"]

  • selectはforで回して実行することも出来る
  • caseは変数を指定しなくてもエラーにならない

[/box]

package main

import (
	"fmt"
	"time"
)

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

forを抜けた後の処理を実行する方法

[box class="glay_box"]

  • returnをbreakに変更しても関数が終了してしまうので、forの後の処理は実行されない
  • 実行するにはforをコロン(:)で指定する必要がある
  • returnをbreakに変更して、指定した値を記載する

[/box]

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("##############")
}
(結果)
    .
    .
tick.
    .
    .
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
BOOM!
##############

Go言語入門-sync.Mutex-

[box class="glay_box"]

  • エラーが発生したり、しなかったりするソースも存在する

[/box]

package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(map[string]int)
	go func() {
		for i := 0; i < 10; i++ {
			c["key"] += 1
		}
	}()
	go func() {
		for i := 0; i < 10; i++ {
			c["key"] += 1
		}
	}()
	time.Sleep(1 * time.Second)
	fmt.Println(c, c["Key"])
}
(結果1)エラー表示
fatal error: concurrent map writes
(結果2)
map[key:20] 0

[box class="glay_box"]

  • 2つのgoroutineから1つのmapを読んだりすると発生するエラー
  • 回避するためにsync.Mutexを使用する
  • 片方の処理が書き込み中の場合にもう片方が書き込めないようにロックする
  • 読み込みの場合も書き込みと同様/li>

[/box]

package main

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

type Counter struct {
	v   map[string]int
	mux sync.Mutex
}

func (c *Counter) Inc(key string) {
	c.mux.Lock()
	defer c.mux.Unlock()
	c.v[key]++
}

func (c *Counter) Value(key string) int {
	c.mux.Lock()
	defer c.mux.Unlock()
	return c.v[key]
}

func main() {
	c := Counter{v: make(map[string]int)}
	go func() {
		for i := 0; i < 10; i++ {
			c.Inc("Key")
		}
	}()
	go func() {
		for i := 0; i < 10; i++ {
			c.Inc("Key")
		}
	}()
	time.Sleep(1 * time.Second)
	fmt.Println(c, c.Value("Key"))
}
(結果)
{map[Key:20] {0 0}} 20

≪ Go言語入門⑮へ

目次

-Go, 入門