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

☑本記事の内容
  • changeとselect
  • Default Selection
  • sync.Mutex
参考資料:現役シリコンバレーエンジニアが教えるGo入門 + 応用でビットコインのシストレFintechアプリの開発

Go言語入門-changeとselect-

  • channelを複数使用する時に利用
  • お互いのchannelは干渉しない
  • 異なる型でも実行可能
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-

基本的なこと

  • selectはforで回して実行することも出来る
  • caseは変数を指定しなくてもエラーにならない
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を抜けた後の処理を実行する方法

  • returnをbreakに変更しても関数が終了してしまうので、forの後の処理は実行されない
  • 実行するにはforをコロン(:)で指定する必要がある
  • returnを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("##############")
}
(結果)
    .
    .
tick.
    .
    .
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
BOOM!
##############

Go言語入門-sync.Mutex-

  • エラーが発生したり、しなかったりするソースも存在する
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
  • 2つのgoroutineから1つのmapを読んだりすると発生するエラー
  • 回避するためにsync.Mutexを使用する
  • 片方の処理が書き込み中の場合にもう片方が書き込めないようにロックする
  • 読み込みの場合も書き込みと同様/li>
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言語入門⑮へ

目次

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です