2016-01-13 18 views
0

下面是一個例子:如何在同一個循環內向/從通道發送和接收值?

func main() { 
    c := make(chan int) 
    i := 0 

    go goroutine(c) 

    c <- i 
    time.Sleep(10 * time.Second) 

} 

func goroutine(c chan int) { 
    for { 
     num := <- c 
     fmt.Println(num) 
     num++ 
     time.Sleep(1 * time.Second) 
     c <- num 
    } 
} 

我試圖夠程中執行的任務是從通道接收號碼,打印,增量和一個後第二次發回的通道。在此之後,我想重複這一行動。

但是,結果是,操作只進行一次。

輸出:

0 

我做錯什麼了嗎?

回答

2

默認情況下,goroutine通信是synchronousunbuffered:直到有一個接收器接受該值,發送才完成。必須有一個接收器準備好接收來自該頻道的數據,然後發送者可以直接將其傳送給接收器。

/接收操作,以便信道發送被阻塞,直到另一側已準備就緒:

1.上的信道塊A發送操作直至一個接收機是可用的相同的信道:如果沒有接收者的值在ch上,沒有其他值可以放在通道中。反過來說:ch當頻道不是空的時候不能發送新的值!所以發送操作將等到ch變爲可用。

2。一個通道的接收操作阻塞,直到一個發送器可用於相同的通道:如果通道中沒有值,則接收器阻塞。

這在下面的示例中被示出:

package main 
import "fmt" 

func main() { 
    ch1 := make(chan int) 
    go pump(ch1) // pump hangs 
    fmt.Println(<-ch1) // prints only 0 
} 

func pump(ch chan int) { 
    for i:= 0; ; i++ { 
     ch <- i 
    } 
} 

因爲沒有接收器的夠程掛起並打印所述第一數量。

要解決這個問題,我們需要定義一個新的goroutine,它從無限循環中的通道讀取數據。

func receive(ch chan int) { 
    for { 
     fmt.Println(<- ch) 
    } 
} 

然後在main()

func main() { 
    ch := make(chan int) 
    go pump(ch) 
    go receive(ch) 
} 

Go Playground

+0

謝謝大家了詳細的解釋。 – RhinoLarva

+2

請注意,在啓動第二個goroutine後,您的最後一個'main()'函數會返回,因此程序可能會立即退出(它不會等待非'main' goroutine完成)。它可能是'pump()'而'receive()'甚至不會被調用。 – icza

1

您使用非緩衝通道,讓你的夠程上c <- num
掛你應該使用緩衝信道,像這樣:c := make(chan int, 1)

嘗試它的Go playground

1

您創建一個無緩衝通道c

c := make(chan int) 

在未緩衝的通道上,操作是對稱的,即通道上的每次發送都需要一個rec eive,每個接收需要一個發送。你發送你的i進入頻道,goroutine收到num。之後,goroutine會將遞增的num發送到該頻道,但沒有人接收該頻道。

總之:語句

c <- num 

將阻止。

你可以使用1緩衝通道,這應該工作。

您的代碼存在另一個問題,您通過在main中等待十秒來解決:您不知道您的goroutine何時完成。通常,在這些情況下使用sync.WaitGroup但是:你的goroutine沒有完成。引入chan struct{}的慣用方法是,您在一段時間後關閉主要門廳,select在工作室門廳的兩個通道上關閉。

相關問題