2016-01-13 20 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在工作室门厅的两个通道上关闭。

相关问题