尝试运行以下代码(生产者和消费者)以了解golang中的goroutine和通道(从下面的代码片段中删除了包和导入):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | var done = make(chan bool) var msgs = make(chan int) func produce() { for i := 0; i < 10; i++ { msgs <- i } fmt.Println("Before closing channel") close(msgs) fmt.Println("Before passing true to done") done <- true } func consume() { for { msg := <-msgs time.Sleep(100 * time.Millisecond) fmt.Println("Consumer:", msg) } } func main() { go produce() go consume() <-done fmt.Println("After calling DONE") } |
源代码来自:http://www.golangpatterns.info/concurrency/producer-consumer
下面是我运行代码时的输出
1 2 3 4 5 6 7 8 9 10 11 12 | Consumer: 0 Consumer: 1 Consumer: 2 Consumer: 3 Consumer: 4 Consumer: 5 Consumer: 6 Consumer: 7 Consumer: 8 Before closing channel Before passing true to done After calling DONE |
根据我对goroutine和渠道的了解:
当我们使用go关键字从main()调用produce()和consume()时,运行时将踢出2个goroutines(Java世界中的某种线程,但不是实际的OS线程),并且main()goroutine出现并在" < -完成"。
现在在Produce()内部-循环从0到9,并且在循环内部msgs通道一次接收由int()并行消耗的int(0至9)1;但是Produce对此一无所知,只是不断循环0到9。
问题:假设我的理解是正确的。一次,fo??r循环完成了,为什么Produce()中的下一个printLine无法打印,以及为什么msgs通道没有关闭?为什么goroutine在Producer()内部停止,直到消费者耗尽了所有msg?
- 生产者中的print语句确实得到打印,并且for循环退出后,msgs通道立即关闭。 我不明白你在问什么。
- 那么,为什么在输出中,在"消费者:8"之后(即在所有味精消耗完之后)打印打印语句"关闭通道之前"和"传递完成之前"?
- 在无缓冲通道上发送和接收是同步的。 该文档可能会有所帮助:golang.org/doc/effective_go.html#channels
很容易看出您是否仅在示例中添加了一些打印语句
http://play.golang.org/p/diYQGN-iwE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | func produce() { for i := 0; i < 4; i++ { fmt.Println("sending") msgs <- i fmt.Println("sent") } fmt.Println("Before closing channel") close(msgs) fmt.Println("Before passing true to done") done <- true } func consume() { for msg := range msgs { fmt.Println("Consumer:", msg) time.Sleep(100 * time.Millisecond) } } |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | sending Consumer: 0 sent sending Consumer: 1 sent sending Consumer: 2 sent sending Consumer: 3 sent Before closing channel Before passing true to done After calling DONE |
-
您也可以通过编辑原件以使其类似于
var msgs = make(chan int, 99) 来查看此内容。具有足够空间的缓冲通道。在这种情况下,主电源可能会在消费者可以消费任何东西之前退出(确切的顺序是不确定的)。 - 完美现在很有意义。感谢您的详细解释,@ JimB。
- 我厌倦了使msgs通道成为缓冲。在consume()中添加了一些打印语句。我看到每次运行代码时,都会打印" fmt.Println("调用DONE之后")",即使在那之后,我仍然可以看到来自consumpt()函数内部的打印语句被打印。在这种情况下,每当" <-done"收到消息时,它不等待任何goroutine完成,这是不正确的吗?那么,为什么在这种情况下,即使收到<-done并且打印了"调用DONE之后",我仍然可以看到consumpt()goroutine继续运行?
-
@srock:使用者可以自由运行直到主返回为止,因此它可以打印出
<-done 与运行时关闭之间的某些行。