Невозможно получить значение из канала - PullRequest
1 голос
/ 16 октября 2019

Я вставляю некоторые значения в канал. после этого я попытался вывести его из канала, но он не получил никакого значения и завершил работу. Кто-нибудь знает, ПОЧЕМУ?

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 ]

3 голосов
/ 16 октября 2019

Возможно, ваш канал закрыт перед добавлением значений в канал (close вызывается перед первой строкой ваших подпрограмм). Тогда, конечно, нечего будет читать на канале. Вместо того чтобы использовать 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 голос
/ 16 октября 2019

В вашем коде есть несколько вещей, на которые стоит обратить внимание.

Первый - это использование переменной s из цикла for в замыкании.

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

Здесь вы можете получить несогласованные значения, поскольку вы не знаете, когда будут выполняться эти программы. Из всего, что вы знаете, вы могли бы написать «С» на канал три раза. Если вы хотите использовать его с отдельными процедурами, используйте его следующим образом:

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)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...