☑本記事の内容
- changeとselect
- Default Selection
- sync.Mutex
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言語入門-Default Selection-
✔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