2014-06-28 100 views
1

我做的圍棋之旅:http://tour.golang.org/#72 這是我的代碼:無緩衝通道

package main 

import (
    "code.google.com/p/go-tour/tree" 
    "fmt" 
) 

// Walk walks the tree t sending all values 
// from the tree to the channel ch. 
func Walk(t *tree.Tree, ch chan int) { 
    var makeWalk func(t *tree.Tree, ch chan int) 

    makeWalk = func(t *tree.Tree, ch chan int) { 
     if t.Left != nil { 
      makeWalk(t.Left, ch) 

     } 
     fmt.Println("-->", t.Value) 
     ch <- t.Value 
     fmt.Println("continue here") 
     if t.Right != nil { 
      makeWalk(t.Right, ch) 
     } 
    } 
    makeWalk(t, ch) 
    close(ch) 
} 

// Same determines whether the trees 
// t1 and t2 contain the same values. 
func Same(t1, t2 *tree.Tree) bool { 
// var ch_l chan int = make(chan int) 
// var ch_r chan int = make(chan int) 
    return false 
} 

func main() { 
    ch := make(chan int) 
    go Walk(tree.New(1), ch)  
    for i := range(ch) { 
     fmt.Println(i) 
    } 
} 

這是輸出:

--> 1 
continue here 
--> 2 
1 
2 
continue here 
--> 3 
continue here 
--> 4 
3 
4 
continue here 
--> 5 
continue here 
--> 6 
5 
6 
continue here 
--> 7 
continue here 
--> 8 
7 
8 
continue here 
--> 9 
continue here 
--> 10 
9 
10 
continue here 

據我瞭解渠道塊當它們被傳遞與價值。我期望看到這樣的輸出:

--> 1 
1 
continue here 
--> 2 
2 
continue here 
... 
--> 10 
10 
continue here 

通道沒有緩衝,是fmt.Println緩衝?這裏發生了什麼? :)

+0

沒有同步機制,因此主函數從通道接收,現在goroutine可以在通道上發送並前進,但是有時會在調用Println之前發生。所以你會得到這種「隨機」的行爲。 –

+0

如果我理解你 - 通道阻塞正確,但發送/接收比'main'中的'Println'更快?順便說一下,同步這個的正確方法是什麼? – Marii

回答

1

當您提到fmt.Println時,您處於正確的軌道上。通道讀取和寫入不是調度程序可以切換到另一個goroutine的唯一時間。阻塞系統調用也可以觸發上下文切換。

FAQ

當協程塊,例如通過調用一個阻塞系統調用, 運行時自動地移動在同一 操作系統線程其他協程到一個不同的,運行的線程所以他們不會 被阻止。

fmt.Println最終會調用阻止系統調用(write()),所以這就是爲什麼你會看到這種行爲。

+0

謝謝,這是有道理的。 :) – Marii