たなしょのメモ

日々勉強していることをつらつらと

Goの学習メモ9

Goメモ

channels

goroutineを理解できず次の単元に来てしまった。
チャネル型について扱っているらしい。なんとなく理解できた

package main

import "fmt"

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

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c

    fmt.Println(x, y, x+y)
}

配列の4番目から6番目の文字を足してxに代入している。

go sum(s[:len(s)/2], c)

配列の1番目から3番目の文字を足してyに代入している。

go sum(s[len(s)/2:], c)

buffer

バッファを付与できるらしい。
メモ帳を作成したりするときに便利かも。

package main

import "fmt"

func main() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

バッファを2より少なくするとエラーになる。

ch := make(chan int, 1)
$ go run buffered-channels.go
fatal error: all goroutines are asleep - deadlock!

close

チャネルはcloseできるらしい。
fibonacci関数が終了したらcloseしてc(xの値をかえしている。)
それをfor文で回している感じ。

package main

import (
    "fmt"
)

func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
    close(c)
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
        fmt.Println(i)
    }
}

select

selectを使うことでgoroutine結果を使ってcase文で判断させることができる?(あまり理解していない)

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

selectはdefaultを使うことができる。

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)
        }
    }
}

.が2回表示されたあとにtickが表示され。
0.005か0.0005秒かぐらいにBOOM!が表示される。

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)
    }
}

sync.Mutex

排他制御ができるらしい。
ただ現時点では難しくてわからない。

package main

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

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

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

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

func main() {
    c := SafeCounter{v: make(map[string]int)}
    for i := 0; i < 1000; i++ {
        go c.Inc("somekey")
    }

    time.Sleep(time.Second)
    fmt.Println(c.Value("somekey"))
}

これで一通りはa tour of goの内容は終わり。
理解の甘い部分がかなりあるので別の教材で補填していく。