-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
-
goroutine
goroutine是轻量级的线程,在相同的内存空间中运行;关键字是gopackage main import ( "fmt" "time" ) func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func main() { go say("world") say("hello") } -
Channels
Channels可以在goroutine传递数据;应用上与node的await相似Channels必须receive (<- chan)和sends (chan <-)共同存在才有意义By default
channelsare unbuffered, which states that they will only accept sends(chan <-)if there is a corresponding receive(<- chan)which are ready to receive the sent value. This allowsgoroutinesto synchronize without explicit locks or condition variables.package main import "fmt" func sum(s []int, c chan int) { sum := 0 for _, v := range s { fmt.Println(v) sum += v } c <- sum // send sum to c } 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 // receive from c fmt.Println(x, y, x+y) } -
Buffered Channels
设置缓冲区,允许多次
sends (chan <-)再多次receive (<- chan)package main import "fmt" func main() { ch := make(chan int, 2) ch <- 1 ch <- 2 fmt.Println(<-ch) fmt.Println(<-ch) } -
Range and Close
sender可以调用close告知channel没有数据要发送了Receiverscan test whether a channel has been closed by assigning a second parameter to the receive expressionv, ok := <-chThe loop for
i := range creceives values from the channel repeatedly until it is closed.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) } }只有
sender可以关闭通道,receiver不可以关闭;在已经关闭的通道发送数据会引发panicChannels aren't like files; you don't usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range loop.
-
Select
select用来监听和channel有关的IO操作,当IO操作发生时,触发相应的动作监听
c和quit两个channelpackage main import "fmt" func fibonacci(c, quit chan int) { x, y := 0, 1 for { select { // send x to c case c <- x: x, y = y, x+y // receive from quit case <-quit: fmt.Println("quit") return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { // receive from c fmt.Println(<-c) } // send 0 to quit quit <- 0 }() fibonacci(c, quit) } -
Default Selection
The default case in a select is run if no other case is ready
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) } } } -
Exercise: Equivalent Binary Trees
package main import "fmt" import "code.google.com/p/go-tour/tree" // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int) { var walker func(t *tree.Tree) walker = func (t *tree.Tree) { if (t == nil) { return } walker(t.Left) ch <- t.Value walker(t.Right) } walker(t) close(ch) } // Same determines whether the trees // t1 and t2 contain the same values. func Same(t1, t2 *tree.Tree) bool { ch1, ch2 := make(chan int), make(chan int) go Walk(t1, ch1) go Walk(t2, ch2) for { v1, ok1 := <-ch1 v2, ok2 := <-ch2 if !ok1 && !ok2 { // no more nodes in trees break } if ok1 != ok2 { // trees with different number of nodes return false } if v1 != v2 { return false } } return true } func main() { fmt.Println("1 and 1 same: ", Same(tree.New(1), tree.New(1))) fmt.Println("1 and 2 same: ", Same(tree.New(1), tree.New(2))) } -
sync.Mutex
What if we just want to make sure only one goroutine can access a variable at a time to avoid conflicts?
如下,变量
a的值并不会依次递增输出。因为goroutine共享内存package main import ( "fmt" "time" ) func main() { var a = 0 for i := 0; i < 1000; i++ { go func(idx int) { a++ fmt.Println(a) }(i) } time.Sleep(time.Second) }加上锁就能确保依次递增输出
package main import ( "fmt" "sync" "time" ) func main() { var a = 0 var lock sync.Mutex for i := 0; i < 1000; i++ { go func(idx int) { lock.Lock() defer lock.Unlock() a++ fmt.Println(a) }(i) } time.Sleep(time.Second) }更优雅方案。换用
channel方案,同时不用Sleeppackage main import ( "fmt" ) func main() { var a = 0 ch := make(chan int) for i := 0; i < 1000; i++ { go func(idx int, ch chan int) { a++ ch <- a }(i, ch) fmt.Println(<-ch) } }