Goの並行処理を実際に試す(3)
引き続きパターンを試す。
1-9-timeout-direct-select.go
// Global timer returns after 5 seconds, stopping execution in select control block
- global timerを使用して5秒後に
block
をtime outさせる
// Kevin Chen (2017) // Patterns from Pike's Google I/O talk, "Go Concurrency Patterns" // Global timer returns after 5 seconds, stopping execution in select control block package main import ( "fmt" "time" ) func main() { ch := generator("Hi!") timeout := time.After(5 * time.Second) for i := 0; i < 10; i++ { select { case s := <-ch: fmt.Println(s) case <-timeout: // time.After returns a channel that waits N time to send a message fmt.Println("5s Timeout!") return } } } func generator(msg string) <-chan string { // returns receive-only channel ch := make(chan string) go func() { // anonymous goroutine for i := 0; ; i++ { ch <- fmt.Sprintf("%s %d", msg, i) time.Sleep(time.Second) } }() return ch }
2-1-quit-select.go
// Deterministically quit goroutine with quit channel option in select
- generatorに設定したオプションでgoroutineを終わらせることが出来る
// Kevin Chen (2017) // Patterns from Pike's Google I/O talk, "Go Concurrency Patterns" // Deterministically quit goroutine with quit channel option in select package main import ( "fmt" "math/rand" ) func main() { quit := make(chan bool) ch := generator("Hi!", quit) for i := rand.Intn(50); i >= 0; i-- { fmt.Println(<-ch, i) } quit <- true } func generator(msg string, quit chan bool) <-chan string { // returns receive-only channel ch := make(chan string) go func() { // anonymous goroutine for { select { case ch <- fmt.Sprintf("%s", msg): // nothing case <-quit: fmt.Println("Goroutine done") return } } }() return ch }
2-2-receive-quit.go
// Deterministically quit goroutine with quit channel option in select
- さっきと同様にoptionを渡してgroutineを終わらせている
// Kevin Chen (2017) // Patterns from Pike's Google I/O talk, "Go Concurrency Patterns" // Deterministically quit goroutine with quit channel option in select package main import ( "fmt" "math/rand" ) func main() { quit := make(chan string) ch := generator("Hi!", quit) for i := rand.Intn(10); i >= 0; i-- { fmt.Println(<-ch, i) } quit <- "Bye!" fmt.Printf("Generator says %s", <-quit) } func generator(msg string, quit chan string) <-chan string { // returns receive-only channel ch := make(chan string) go func() { // anonymous goroutine for { select { case ch <- fmt.Sprintf("%s", msg): // nothing case <-quit: quit <- "See you!" return } } }() return ch }
2-3-daisy-chain.go
// Daisy chaining goroutines... all routines at once, so if one is fulfilled // everything after should also have their blocking commitment (input) fulfilled
- channnelを使用して先に走らせたgoroutineで計算
- rightが書き込まれるまでblockされている
// Kevin Chen (2017) // Patterns from Pike's Google I/O talk, "Go Concurrency Patterns" // Daisy chaining goroutines... all routines at once, so if one is fulfilled // everything after should also have their blocking commitment (input) fulfilled package main import ( "fmt" ) // takes two int channels, stores right val (+1) into left func f(left, right chan int) { left <- 1 + <-right // bafter 1st right read, locks until left read } func main() { const n = 10000 // construct an array of n+1 int channels var channels [n + 1]chan int for i := range channels { channels[i] = make(chan int) } // wire n goroutines in a chain for i := 0; i < n; i++ { go f(channels[i], channels[i+1]) } // insert a value into right-hand end go func(c chan<- int) { c <- 1 }(channels[n]) // get value from the left-hand end fmt.Println(<-channels[0]) }
2-4-google-search.go
// Using go patterns with experiment 'Google Search' i.e concurrent goroutines getting results
- Google Searchぽいことを体感させるぽい
// Kevin Chen (2017) // Patterns from Pike's Google I/O talk, "Go Concurrency Patterns" // Using go patterns with experiment 'Google Search' i.e concurrent goroutines getting results package main import ( "fmt" "math/rand" "time" ) var ( Web = fakeSearch("web") Web2 = fakeSearch("web") Image = fakeSearch("image") Image2 = fakeSearch("image") Video = fakeSearch("video") Video2 = fakeSearch("video") ) type Result string type Search func(query string) Result func main() { rand.Seed(time.Now().UnixNano()) start := time.Now() results := Google("golang") // collate results elapsed := time.Since(start) fmt.Println(results) fmt.Println(elapsed) } func fakeSearch(kind string) Search { return func(query string) Result { time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) return Result(fmt.Sprintf("%s result for %q\n", kind, query)) } } func First(query string, replicas ...Search) Result { c := make(chan Result) searchReplica := func(i int) { c <- replicas[i](query) } for i := range replicas { go searchReplica(i) } return <-c } func Google(query string) (results []Result) { c := make(chan Result) go func() { c <- First(query, Web, Web2) }() go func() { c <- First(query, Image, Image2) }() go func() { c <- First(query, Video, Video2) }() timeout := time.After(80 * time.Millisecond) for i := 0; i < 3; i++ { select { case result := <-c: results = append(results, result) case <-timeout: fmt.Println("timed out") return } } return }
一応乗っかってるの全部できた。