无法从渠道获得价值

时间:2019-10-16 07:12:30

标签: go

我在通道中插入了一些值。之后,我尝试将其从通道中删除,但没有得到任何值并退出。有人知道为什么吗?

package main
import (
    "fmt"
)
func main() {
    c := make( chan string)
    for _, s := range []string{"A", "B", "C"} {
        fmt.Println( "input : ", s)
        go func() {
            c <- s 
        }()
    }
    close( c)
    // recive
    for i := range c {
        fmt.Println("output", i)
    }
}

期望输出

input :  A
input :  B
input :  C
output : A
output : B
output : C

当前输出

input :  A
input :  B
input :  C

2 个答案:

答案 0 :(得分:3)

在您在通道中添加值之前,您的通道可能已关闭(close在goroutine的第一行之前被调用)。然后,当然在该频道中没有任何内容可读取。 不用使用goroutines在通道中添加值,您可以切换到这样的缓冲通道:

package main
import (
    "fmt"
)
func main() {
    inputs := []string{"A", "B", "C"}
    c := make(chan string, len(inputs))
    for _, s := range inputs {
        fmt.Println( "input : ", s)
        c <- s 
    }
    close(c)
    // recive
    for i := range c {
        fmt.Println("output", i)
    }
}

或者您可以像这样使用WaitGroup:

package main
import (
    "fmt"
    "sync"
)
func main() {
    var wg sync.WaitGroup
    inputs := []string{"A", "B", "C"}
    c := make(chan string)
    for _, s := range inputs {
        fmt.Println( "input : ", s)
        wg.Add(1)
        go func(s string) {
            c <- s
            wg.Done()
        }(s)
    }
    go func(){
        wg.Wait()
        close(c)
    }()

    // recive
    for i := range c {
        fmt.Println("output", i)
    }
}

答案 1 :(得分:1)

代码中有几件事需要注意。

第一个是闭包中for循环中s变量的用法。

go func() {
            c <- s 
        }()

在这里,您可能会得到不一致的值,因为您不知道何时执行这些goroutine。据您所知,您最终可能会在该通道上写3次“ C”。如果要与单独的goroutine一起使用,请按以下方式使用它:

go func(str string) {
                c <- str 
            }(s)

对于未从通道中检索到的值,通道将关闭,然后才能从通道中检索任何值。您可以这样写:

package main
import (
    "fmt"
)
func main() {
    c := make( chan string)
    go func(){
      for _, s := range []string{"A", "B", "C"} {
        fmt.Println( "input : ", s)
        c <- s 
      }
      close( c)
    }()
    // recive
    for i := range c {
        fmt.Println("output", i)
    }
}

但是,即使那样,您也会得到这样的输出(甚至可能有所不同):

input :  A
input :  B
output A
output B
input :  C
output C

要获得所需的输出,可能需要使用缓冲的通道和某种机制来防止读取,直到所有内容都写入通道为止。也许是这样的:

package main
import (
    "fmt"
    "sync"
)
func main() {
    c := make( chan string,3)
    var wg sync.WaitGroup
    wg.Add(3)
    for _, s := range []string{"A", "B", "C"} {
        fmt.Println( "input : ", s)
        c <- s 
    }


    go func(w *sync.WaitGroup){
      // recive
      for i := range c {
        fmt.Println("output", i)
        w.Done()
      }
    }(&wg)

    wg.Wait()
    close(c)
}