Golang:关于频道的一些问题

时间:2013-11-21 06:21:20

标签: recursion concurrency go fibonacci channel

http://play.golang.org/p/uRHG-Th_2P

我很难理解频道的概念

package main

import (
  "fmt"
)

func Fibonacci(limit int, chnvar chan int) {
  x, y := 0, 1
  for i := 0; i < limit; i++ {
    chnvar <- x
    x, y = y, x+y
  }
  close(chnvar)

  v, ok := <-chnvar
  fmt.Println(v, ok)
}


func main() {
  chn := make(chan int, 10)
  go Fibonacci(cap(chn), chn)
  for elem := range chn {
    fmt.Printf("%v ", elem)
  }
}
//1 1 2 3 5 8 13 21 34 

1) 如何从行

中获取错误值
v, ok := <-chnvar

如果没有更多的值可以说它是假的。 如果频道关闭,也是假的。 但在这种情况下,渠道已经关闭,但(?)仍然可以获得真正的价值。

如果我把它拿出来,就会感到恐慌。

这里如何以及为什么会返回true?

2) 这条线

 go Fibonacci(cap(chn), chn)

也可以在没有goroutine的情况下运行。 有什么不同?只是表现问题。

提前致谢

2 个答案:

答案 0 :(得分:1)

  1. 您的Fibonacci函数将10个值填充到通道中(其缓冲区为10个值),然后将其关闭。假设在主goroutine从通道中读取所有内容之前执行v, ok <- chnvar语句(非常可能,但不能保证),将会有一个值读取,因此ok将为真。

    如果删除close调用,主goroutine中的for循环将最终清空通道的缓冲区并阻塞等待更多数据。由于没有其他goroutine活动写入通道,运行时会将此检测为死锁。

  2. 您的示例程序直接调用Fibonacci运行(而不是作为goroutine),因为它写入的通道是缓冲的,并且它永远不会超出缓冲区。因此,它可以在不阻塞的情况下完成,并允许执行继续执行main函数的其余部分。

    如果频道没有被缓冲,或者你写的值多于缓冲区中的值,那么Fibonacci将阻止等待其他goroutine从频道中读取内容。

答案 1 :(得分:0)

<强> 1)

Go规范说明了频道接收操作(我的重点):

  

x,ok:=&lt; -ch

     

如果接收到的值是通过成功的发送操作传递给通道,则ok的值为true;如果由于通道关闭为空而产生的零值,则为false。

也就是说,因为缓冲的通道不为空并且您已成功接收到值(0),ok将为真。在渠道清空之前,您不会收到错误。

<强> 2)

通过在其自己的Go例程中运行Fibonacci(cap(chn), chn),main可以开始接收和处理(打印出)值,而Fibonacci函数仍在向通道提供新值。
在你的情况下,这可能永远不会发生,因为函数将填充缓冲区并在main有机会处理任何内容之前完成。

如果它不会在Go例程中运行,Fibonacci首先需要生成所有值,然后才能由main进一步处理。