Go ã®ä¸¦è¡å¦ç
intro
å æ¥ã® Go ã®ã«ã³ãã¡ã¬ã³ã¹ GoCon ã§ã Go ã®ä¸¦è¡å¦çå¨ãã«ã¤ãã¦çºè¡¨ããã¦é ãã¾ããã
Go Conference 2013 spring - connpass
å
·ä½çã«ã¯ Goroutine ã Channel ã®è©±ã§ããããããã®æ©è½ã¯çµæ§é¢ç½ãã¦ãããã£ã¦éãã§ãã ãã§ããããããã¾ãã
Go ã®ä¸¦è¡å¦çã¯ãè¨è¨æ¹éãããã¨ç¹æ®ã ã¨æãã®ã§ãããè¨è¨ãã·ã³ãã«ãªã®ã§åããã¨ããã¾ã§é£ããã¯ãªãã§ãã
(使ãããªãã®ã¯ãçµé¨ãå¿
è¦ããã§ãã)
ä»å話ãã«ããã£ã¦è²ã
調ã¹ã¾ããããçºè¡¨æéã®é½åä¸çãããã®ããããã質çå¿çã§èããã¦å¿ããããªãã£ããã¨ãããã®ã§ã
ããã§ã¾ã¨ãã¦ç½®ããã¨æãã¾ãã
çºè¡¨è³æ
ä»åã®çºè¡¨è³æã¯ãã¡ãã§ãã
ãã®ããã°ã®å
容ã¯ãããããã¼ã¹ã«ãã¾ãã
http://jxck.node-ninja.com/slides/gocon-2013spring.html
ã½ã¼ã¹ã¯ãããã«ã¾ã¨ãã¾ããã
Go ã® Concurrency Model
並è¡å¦çããã°ã©ãã³ã°ã«ã¯ããã£ããåãã¦äºã¤ã®ã¢ããã¼ããããã¾ãã
- Shared-memory communication
- ã¯ã¼ã«éã§ã¡ã¢ãª(ãªã½ã¼ã¹) ãå ±æãããã¬ã¼ã¹ã³ã³ãã£ã·ã§ã³ãèµ·ãããªãããã«ããã¯ãã¨ããã¨ãå¤ãããã®å®è£ ã¯é£ãããã¨ãå¤ãã¨ãããã
- Message-passing communication
- ã¯ã¼ã«éã§ã¡ãã»ã¼ã¸ããã·ã³ã°ãè¡ããErlang ãªã©ã«å®è£ ããã Actor ã¢ãã«ãªã©ã代表çãªå®è£ ã
ããã¦ãGo ã®ä¸¦è¡å¦çã¢ãã«ã®æ¹éã¯ä¸è¨ã«å®£è¨ããã¦ãã¾ãã
"Do not communicate by sharing memory; instead, share memory by communicating"
ãªã®ã§ãä¸è¨ã§è¨ãã¨å¾è
ãªã®ã§ããã Erlang ã® Actor ã¢ãã«ãªã©ã¨ã¯ç°ãªãç¹ãããã¤ãããã¾ãã
Go ã§ã®å®è£ ã«ã¯ãä¸è¨ã®äºã¤ãåèã«ããã¦ãã¾ãã
- CSP (Communicating Sequential Processes)
- 並è¡å¦çã®ããã®è¨è¨çè«ãå®è£ ã¨ãã¦ã¯ Occam, Limbo ãªã©ãããã
- π caluculus
- ãã¡ãã並è¡å¦çã®ããã®çè«ãErlang ã®ã¡ãã»ã¼ã¸ã³ã°ã ! ãªã®ã¯ãããå ã«ãªã£ã¦ããããæ¥æ¬èªã®æ å ±ãªãããA Very Brief Introduction to the Pi-Calculus (in Japanese)ã
ããããå®ç¾ããããã«ã Go ã«ã¯ä»¥ä¸ã®æ©è½ãå®è£
ããã¦ãã¾ãã
- goroutine
- channel
ã¾ãã以ä¸ã®äºã¤ããããããå¼·åã«ãã¾ãã
- select
- closure
Goroutine
Goroutine ã¨ã¯
- Coroutine ã§ã¯ãªãã
- Thread, Process ã§ããªãã
- è¤æ°ã® Thread ä¸ã«å¤éåããã¦å®è£ ããã¦ãã
- main() èªèº«ã Scavenger(GC) ãªã©ã©ã³ã¿ã¤ã ã goroutine ã使ã£ã¦ãã
ä¸è¨å¨ãã®è©±ã¯ãèªåã®ãã¨ã® methane ããã®çºè¡¨ã®æ¹ã詳ããã£ãã®ã§ããã¡ããåç
§ãã¦ä¸ããã
https://gist.github.com/methane/5377227#file-goscheduler-md
go æã§ã®èµ·å
goroutine 㯠go æã§é¢æ°ãå®è¡ããã¨èµ·åã§ãã¾ãã
go æã¯ãããã¯ããªãã®ã§ã goroutine ã¯éåæã«èµ·åããã¾ãã
ä¸è¨ã® main() ã§ã¯ãgoroutine ãäºã¤èµ·åãã¦ãã time.Sleep() ã§ä¸æåæ¢ãã¦ããã®ã¯ããããç¡ãã£ãã f() ãå®è¡ãããåã« main() ãçµãã£ã¦ãã¾ãããã§ãã
goroutine ãä»ã«å®è¡ããã¦ããã㨠main() ãçµããã¨ããã»ã¹ãçµäºãã¾ãã
func f(msg string) { log.Println(msg) } func main() { go f("hello") go func() { log.Println("gopher") }() time.Sleep(time.Second) }
https://github.com/Jxck/goroutine-sample/blob/master/goroutine.go
goroutine ã®çµäºæ¡ä»¶
goroutine ã¯ãä¸è¨ã®æ¡ä»¶ã§çµäºãã¾ãã
- é¢æ°ãçµãã
- return ã§æãã
- runtime.Goexit() ãå®è¡ãã
func main() { go func() { log.Println("end") }() go func() { log.Println("return") return }() go func() { log.Println("exit") runtime.Goexit() }() time.Sleep(time.Second) }
https://github.com/Jxck/goroutine-sample/blob/master/goroutine-exit.go
runtime.NumGoroutine
ç¾å¨èµ·åãã¦ãã goroutine ã®æ°ãç¥ããã¨ãã§ãã¾ãã
func main() {
log.Println(runtime.NumGoroutine())
}
ãããå®è¡ããã¨ãèªåã®ç°å¢ã§ã¯ 2 ã¨åºã¾ããã
ã¾ãã main() ãã®ãã®ã goroutine ãªã®ã§ã 1 ã¤ã¯ãããã¾ãã
ãããããã 1 ã¤ã¯èª°ã§ãããï¼ äºã¤ã®é¢æ°ã使ã£ã¦ã¾ããããããã goroutine ã¯ä½¿ã£ã¦ã¾ããã
ML ã§èãã¦ã¿ãã¨ããã bradfitz ãããå¿ãã¦ããã¾ããããããªå¤§ç©ã®è¿ä¿¡ãããããã¨ããã
çµæããè¨ãã¨ãä¸è¨ã«å¤ããã¨åããã¾ãã
func main() { log.Println(runtime.NumGoroutine()) select{} }
ããã GOTRACEBACK=2 ãã¤ãã¦å®è¡ãã¾ãã
GOTRACEBACK=2 go run numgoroutine.go
åºåãé·ãã®ã§ã®ãã¾ããããè¦ã㨠runtiem.main() 以å¤ã« runtime.MHeap_Scavenger() ãåãã¦ãäºããããã¾ãã
ãã®ããã«ã go æã§èµ·åãã goroutine ã main() 以å¤ã«ãã Scavenger (GC) ãªã©ã©ã³ã¿ã¤ã ç°å¢ã§ã goroutine ã使ããã¦ãããã¨ããããã¾ãã
ãã®æ
å ±ã¯ã runtime.Stack ãããåãã¾ãã
func main() { log.Println(runtime.NumGoroutine()) buf := make([]byte, 1<<20) buf = buf[:runtime.Stack(buf, true)] log.Println(string(buf)) select {} }
Channel
Channel ã¨ã¯
- Channel 㯠goroutine éã§ã®ã¡ãã»ã¼ã¸ããã·ã³ã°ãããããã®ãã®
- ã¡ãã»ã¼ã¸ã®åãæå®ã§ãã
- first class value ã§ãããå¼æ°ãæ»ãå¤ã«ã使ãã
- send/receive ã§ãããã¯ãã
- buffer ã§ãä¸åº¦ã«æ±ããã¡ãã»ã¼ã¸éãæå®ã§ãã
Channel ãç¨ããã¡ãã»ã¼ã¸ã³ã°
Channel ã¯åç
§åãªã®ã§ make() ã§ã¤ã³ã¹ã¿ã³ã¹ãçæãã¾ãã
使ãæ¹ã¯ç°¡åã§ãéä¿¡ã "channel<-value" ã§åä¿¡ã "<-channel" ã§ãã
ä¸è¨ã¯ã goroutine 㨠main() éã§ã®ã¡ãã»ã¼ã¸ã³ã°ã§ãã
main() ã®æå¾ã§ã¯åä¿¡çµæãåºåãã¦ããããã®åä¿¡ã§å¤ãå±ãã¾ã§ãããã¯ããã®ã§ã time.Sleep() ã¯å¿
è¦ç¡ãç¹ã«æ³¨æãã¦ä¸ããã
func f(ch chan bool) { ch <- true } func main() { ch := make(chan bool) go f(ch) log.Println(<-ch) // ããã§ãã¼ã¿ãæ¥ãã¾ã§ãããã¯ãã }
https://github.com/Jxck/goroutine-sample/blob/master/channel.go
åæ
channel ã¯ãéåä¿¡ãå®äºããã¾ã§ãããã¯ãã¾ãã
ãã®ãã¨ãã goroutine éã®åæã«å¿ç¨ãããã¨ãã§ãã¾ãã
ä¸è¨ã¯ã main() ã channel ãåä¿¡ããäºã§ goroutine ã®çµäºãå¾
ã¤åæããã¦ãã¾ãã
åä¿¡ããå¤èªä½ã¯å¿
è¦ãªããããæ¨ã¦ã¦ãã¾ãã goroutine 㯠channel ã closure ã§åç
§ãã¦ãã¾ããclosure ãããã¨æ¬å½ã«ä¾¿å©ã§ããã
func main() { fin := make(chan bool) go func() { log.Println("worker working..") fin <- false }() <-fin }
https://github.com/Jxck/goroutine-sample/blob/master/finchannel.go
ä¸è¨ã¯ã goroutine ã 1 ã¤ã§ãããè¤æ°ããå ´åã¯æ°ã管çããªãã¨ãããªããªãã¾ãã
ãããè¡ãå ´å㯠sync.WaitGroup ã¨ããã¢ã¸ã¥ã¼ã«ã使ç¨ã§ãã¾ãã
func main() { var wg sync.WaitGroup for i:=0; i<3; i++ { wg.Add(1) // goroutine ãçæãããã³ã¤ã³ã¯ãªã¡ã³ã go func(i int) { log.Println(i) wg.Done() // çµäºæã«ãã¯ãªã¡ã³ã }(i) } wg.Wait() // ãããã¯ããå ¨ã¦ã® Done ãçµãã£ãã次ã«é²ã }
https://github.com/Jxck/goroutine-sample/blob/master/waitGroup.go
sync.WaitGroup 㯠channel ã使ã£ã¦ããããã§ã¯ãªãããã§ãã
sync ããã±ã¼ã¸ã«ã¯ã lock ãã¨ã£ããããããã±ã¼ã¸ããã®ã§ã channel ã使ããããã§ãªã½ã¼ã¹å
±æ/åæããããã¨ãã§ãã¾ãããæåã«è¿°ã¹ãããã« Go ã§ã¯æ¥µåã¡ãã»ã¼ã¸ã³ã°ã§ãªã½ã¼ã¹å
±æ/åæããã¾ãããã
Worker ã®èµ·å
ä¸è¨ã¯ãã¯ã¼ã«ã 3 ã¤èµ·åããããããã®å¦ççµæã main() ã§åãåã£ã¦ãã¾ãã
worker() ã go æã§å®è¡ããçµæã渡ãã¦ãããããã® channel ã渡ãã®ã§ã¯ãªãã worker ãå
é¨ã§ãçµæã渡ãããã® channel ãçæããããè¿ãã¦ããã®ã§ã main() ã¯ããããåãåºãã¦ãã¾ãã
func worker(msg string) <-chan string { receiver := make(chan string) for i := 0; i < 3; i++ { go func(i int) { msg := fmt.Sprintf("%d %s done", i, msg) receiver <- msg }(i) } return receiver } func main() { receiver := worker("job") for i := 0; i < 3; i++ { log.Println(<-receiver) } }
https://github.com/Jxck/goroutine-sample/blob/master/workers.go
worker ã®å®£è¨ã«æ³¨ç®ãã¦ä¸ããã
// func worker(msg string) chan string ããã§ã¯ãªã func worker(msg string) <-chan string
worker ãè¿ãåã¯ãèªã¿åãå°ç¨ã® channelãã§ãã(<- ãã¤ãã¦ã)
ããã«ããã main() ããã® channel ã«èª¤ã£ã¦ãã¼ã¿ãæ¸ãè¾¼ããã¨ãé²ãã¾ãã
è¤æ°ã® channel 㨠select
å
ã®ä¾ã§ã¯ã worker 㯠3 ã¤ã®ã¡ãã»ã¼ã¸ãè¿ããã¨ãäºãåãã£ã¦ããã®ã§ã 3 ã¤ã ãåãåºãã¦ãã¾ããã
ãããã worker ãäºãããããªãå ´åãªã©ãããã¾ãã
ãã®å ´åã¯ãç¨éã®éãå¥ã® channel ãè¿ããã¨ã§ãå¿
è¦ãªã¡ãã»ã¼ã¸ãã¨ããã¨ãã§ãã¾ãã
Go ã§ã¯ãé¢æ°ãè¤æ°ã®å¤ãè¿ããã¨ãã§ããããã以ä¸ã®ä¾ã¯ worker ãçµãã£ããã¨ãè¿ãããã® channel ã worker ãè¿ãããã«ãã¦ãã¾ãã
main() ã§ã¯ãè¤æ°ã®ãã£ãã«ããã®ã¡ãã»ã¼ã¸ãåä¿¡ããå¿
è¦ãããã¾ããããããããããã¯ãã¦ãã¾ãã¾ãããããªå ´åã¯ã select ã¨ããæ§æã使ãã¨ãè¤æ°ã® channel ã®åä¿¡ãåæã«è¡ããã¨ãã§ãã¾ãã
func worker(msg string) (<-chan string, <-chan bool) { var wg sync.WaitGroup receiver := make(chan string) fin := make(chan bool) go func() { for i := 0; i < 3; i++ { wg.Add(1) go func(i int) { msg := fmt.Sprintf("%d %s done", i, msg) receiver <- msg wg.Done() }(i) } wg.Wait() fin<-false // çµäºãä¼ãã }() return receiver, fin } func main() { receiver, fin := worker("job") for { select { case receive := <-receiver: log.Println(receive) case <-fin: // çµäºãããçµãã return } } }
https://github.com/Jxck/goroutine-sample/blob/master/finchannel.go
Channel ã® close()
close() ã¯çµã¿è¾¼ã¿ã®é¢æ°ã§ãç¨ã®æ¸ãã channel ãéãããã¨ãã§ãã¾ãã
ãããã channel ã®å¼ã³åºã㯠2 ã¤ã®å¤ãåãåãã¾ãã
message, ok := <-channel
ãã® 2 ã¤ãã® ok ã¯ã channel ãéãããã¦ãããã表ã bool ã§ãã
ok ã¯ãåã£ã¦ãåããªãã¦ãè¯ãä»æ§ã«ãªã£ã¦ãã¾ãã
channel ã close() ããå ´åãåä¿¡å´ã«ã¯ 空ã®ã¡ãã»ã¼ã¸ã¨ false ã渡ãã®ã§ãããã使ã£ã¦ channel ã close() ããããã¨ãå¤å®ã§ãã¾ãã
ã
å
ã»ã©ã®ä¾ã close ã使ã£ã¦æ¸ãç´ãã¨ä»¥ä¸ã«ãªãã¾ãã
func worker(msg string) (<-chan string) { var wg sync.WaitGroup receiver := make(chan string) go func() { for i := 0; i < 3; i++ { wg.Add(1) go func(i int) { msg := fmt.Sprintf("%d %s done", i, msg) receiver <- msg wg.Done() }(i) } wg.Wait() close(receiver) }() return receiver } func main() { receiver := worker("job") for { receive, ok := <-receiver if !ok { log.Println("closed") return } log.Println(receive) } }
https://github.com/Jxck/goroutine-sample/blob/master/close.go
timeout
éãã worker ãããå ´åã worker ããã®çµäºéç¥ãåãåããã«ãä¸å®æéçµéãããçµããããå ´åãããã¾ãã
ãããªæã¯ã time.After ã¨ããé¢æ°ã使ããã¨ãã§ãã¾ãã
time.After ã®åã¯ä»¥ä¸ã§ãã
func After(d Duration) <-chan Time
ä¸å®æéçµéãããã¡ãã»ã¼ã¸ãéã channel ãè¿ãã®ã§ããã® channel ãåãåã£ã¦åä¿¡ããã¦ããã°ãä¸å®æéå¾ã«å¦çãããããã®ããªã¬ã¼ã«ã§ãã¾ãã
ãããç¨ã㦠1 ç§å¾ã« timeout ããããã«æ¸ãæãã¦ã¿ã¾ãã
func randomTime() time.Duration { return time.Duration(rand.Intn(1e3)) * time.Millisecond } func worker(msg string) <-chan string { receiver := make(chan string) for i := 0; i < 300; i++ { go func(i int) { time.Sleep(randomTime()) msg := fmt.Sprintf("%d %s done", i, msg) receiver <- msg }(i) } return receiver } func main() { receiver := worker("job") for { select { case receive := <-receiver: log.Println(receive) case <-time.After(time.Second): // ä¸å®æéçµéãããåä¿¡ log.Println("timeout") return // åä¿¡æã«çµããã° timeout å¦çã«ãªãã } } }
https://github.com/Jxck/goroutine-sample/blob/master/timeout.go
Buffer
Channel ã¯ã make() æã« buffer ãæå®ãããã¨ãã§ãã¾ãã
ãã® buffer ã®å¤ã¯ãä¸åº¦ã« channel ã«æ¸ãè¾¼ãã message ã®ä¸éå¤ã«ãªãã¾ãã
ããã©ã«ã㯠0 ã§ããæå®ããã¨ã MQ ã®ããã«æ±ããã¨ãã§ããã¤ã¡ã¼ã¸ã§ãã
é信㯠buffer ãä¸æ¯ã ã£ãå ´åã¯éä¿¡ã§ãããã¯ãã¾ãã
ãããå©ç¨ãã¦ãä¾ãã° worker ãåæã«èµ·åããæ°ãå¶éã§ãã¾ãã
以ä¸ã¯ã 100 åã®å¦çãåæã« 5 ã¤ã ãã® goroutine ãèµ·åãã¦è¡ããµã³ãã«ã§ãã
func worker(msg string) <-chan string { limit := make(chan int, 5) receiver := make(chan string) go func() { for i := 0; i < 100; i++ { log.Println(runtime.NumGoroutine()) limit <- 1 go func(i int) { msg := fmt.Sprintf("%d %s done", i, msg) receiver <- msg <-limit }(i) } }() return receiver } func main() { receiver := worker("job") for i := 0; i < 100; i++ { log.Println(<-receiver) } }
https://github.com/Jxck/goroutine-sample/blob/master/buffer.go
runtime.NumGoroutine() ã®çµæã¯å¿
ããã 5 ã«ãªããªãç¹ã¯åè¿°ã®éãã
Pattern ç·¨
ãããããã¿ã¼ã³ããããã¾ã§ã®å
容ã使ã£ã¦å®è£
ãã¦ã¿ã¾ãã
coroutine
coroutine ã¨è¨ãã° Lua ã§ãããã
ã¹ã±ã¸ã¥ã¼ã«ãè¨è¿°ãããã¨ã§ãå¦çãéä¸ã§æ¢ãã¦ããããããªã¹ã¿ã¼ããããã¨ãã§ãã¾ãã
åç´ãªä¾ã Lua ã§æ¸ãã¨ãããªæãã§ãã
f() ã®ä¸ã®å¦çãéä¸ã§ä¸æããããããåéãã¦ããä¾ã§ãã
function f() coroutine.yield "one" coroutine.yield "two" coroutine.yield "three" return end local co = coroutine.wrap (f) print (co ()) -- one print (co ()) -- two print (co ()) -- three
https://github.com/Jxck/goroutine-sample/blob/master/coroutine.lua
Go ã§ã¯ channel ããããã¯ãããã¨ãå©ç¨ãã¾ãã
func f(yield chan string) { yield <- "one" yield <- "two" yield <- "three" } func main() { co := make(chan string) go f(co) log.Println(<-co) // one log.Println(<-co) // two log.Println(<-co) // three }
https://github.com/Jxck/goroutine-sample/blob/master/coroutine.go
generator
generator ã¯ãå¤ãã®å ´åé åã®ããã«æ±ãã¾ãããæ±ãå¤ãå®è¡æã«çæããã¦ããç¹ãé åã¨éãã¾ããäºãå¤ãçæããªããã¨ã«ãããã¡ã¢ãªæ¶è²»ãå°ãªãã®ãç¹å¾´ã§ãã
10 ã¾ã§å¤ãåãåºãã generator ã¯ã python ã ã¨ä»¥ä¸ã®ããã«ãªãã¾ãã
def generator(n): i = 0 while True: if i > n: break yield i i += 1 for i in generator(10): print i
https://github.com/Jxck/goroutine-sample/blob/master/generator.py
Go ã§ã¯ãã¯ãã channel ã®ãããã¯ã使ãã¾ãã
func generator(n int) chan int { ch := make(chan int) i := 0 go func() { for { ch <- i i++ if i > n { close(ch) break } } }() return ch } func main() { for x := range generator(10) { log.Println(x) } }
https://github.com/Jxck/goroutine-sample/blob/master/generator.go
make() ã®é¨å㧠buffer ãæå®ãã¦ããªãã®ã§ãåæã« 1 ã¤ããçæãããªããã¨ãä¿è¨¼ã§ãã¾ãã(ã¨ãããã¨ã¯çæããæ°ãæå®ãããã¨ãã§ãã)
ãã®ä»
multi-core
ç¾æç¹ã§ã¯ã goroutine ããã«ãã³ã¢ãèªåçã«ä½¿ãããªããããªæé©åã¯ãããªãããã§ãã
ããã goroutine ãè¤æ°ã®ã³ã¢ã§å®è¡ãããå ´å㯠GOMAXPROC ç°å¢å¤æ°ãã runtime.GOMAXPROCS() ã«ã³ã¢æ°ãæå®ãã¾ãã
ãã£ã¦ãã½ã¼ã¹ã«ä»¥ä¸ã®ããã«æ¸ããã¨ãå¤ãã§ãã
cpus := runtime.NumCPU() runtime.GOMAXPROCS(cpus)
ãã³ã
goroutine ã®ã¡ã¢ãªä½¿ç¨éã調ã¹ã¾ãã
ãã¡ãã«ãã£ãã®ããåããã¦ãå°ãå¤ãã¦ã¿ã¾ããã
https://gist.github.com/jgrahamc/5253020
func main() { cpus := runtime.NumCPU() runtime.GOMAXPROCS(cpus) count := 1000 * 100 var startMemory runtime.MemStats runtime.ReadMemStats(&startMemory) start := time.Now() fin := make(chan bool) for i := 0; i < count; i++ { go func() { <-fin }() } elapsed := time.Since(start) var endMemory runtime.MemStats runtime.ReadMemStats(&endMemory) close(fin) fmt.Printf(` goroutine: %d cpu: %d time: %f memory all: %f MB memory: %f byte/goroutine `, count, cpus, elapsed.Seconds(), float64(endMemory.Alloc-startMemory.Alloc)/float64(1024*1024), float64(endMemory.Alloc - startMemory.Alloc)/float64(count)) }
https://github.com/Jxck/goroutine-sample/blob/master/goroutine-bench.go
100,000 åã® goroutine ãèµ·åãã¦ããã®æéã¨ã¡ã¢ãªã®ä½¿ç¨éãè¦ã¦ãã¾ãã
æå
ã® Mac OSX Lione Core 2 Duo, Memory 4G ã§å®è¡ãã¦ã¿ãçµæã以ä¸ã§ãã
goroutine: 100000 cpu: 2 time: 0.589367 memory all: 23.001915 MB memory: 241.192560 byte/goroutine
ããªããå°ããäºããããã¾ããã
ã¨ãããä¸å®ãªã®ã§ããå°ã調ã¹ã¦ã¿ã¾ã(æ±)
outro
goroutine 㨠channel èªä½ã®ä»æ§ã¯ãããªã«é£ãããã®ã§ã¯ããã¾ãããã 2 ã¤ãã使ã£ã¦ãããªãè²ã 表ç¾ã§ãããã¨ãåãã£ã¦é ããã¨æãã¾ããã¾ãã select ã closure ã¨ãã£ãæ©è½ãå°å³ã«ååãªã®ã§ãçµã¿åãããã¨ããã«è²ã ã§ããããã«ãªãã¾ãã
ã¨ãããã¾ã§ãçºè¡¨ã®ç¯å²ã§ãããã¾ã ããã¤ãããã®ã§ãå¾ã§è¿½è¨ãã¦ããã¾ãã
go ã®å£²ãã® 1 ã¤ã§ãããããã®çµã¿è¾¼ã¿ã®ä¸¦è¡å¦çæ©è½ã®ä½¿ãæ¹ããªãã¨ãªãã§ãä¼ããã°ã¨æãã¾ãã
åè
- http://talks.golang.org/2012/concurrency.slide
- http://www.slideshare.net/jgrahamc/go-oncurrency
- https://dl.google.com/googleio/2010/tech-talks-go-programming.pdf
- https://sites.google.com/site/gopatterns/
- http://www.softwareresearch.net/fileadmin/src/docs/teaching/SS10/Sem/Paper__aigner_baumgartner.pdf