无法从通道获取值

问题描述 投票:1回答:2

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

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
go
2个回答
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
投票

您的代码中有几点需要注意。

第一个是在闭包中使用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)
}
© www.soinside.com 2019 - 2024. All rights reserved.