Почему отложенная функция не выполняется? - PullRequest
0 голосов
/ 21 марта 2020

Я изо всех сил пытаюсь понять параллелизм в Go.

package main

import "fmt"

func sendValues(myIntChannel chan int) {
    for i := 0; i < 5; i++ {
        myIntChannel <- i //sending value
    }
}

func main() {
    myIntChannel := make(chan int)
    defer close(myIntChannel)
    go sendValues(myIntChannel)

    for value := range myIntChannel {
        fmt.Println(value) //receiving value
    }
}

Выше код дает следующий вывод:

0
1
2
3
4
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
    /Users/spikki/Desktop/GoLearning/go_channel.go:51 +0x10b

Насколько я понимаю, функция отсрочки будет выполняться после завершение окружающих его функций. Я не могу его интерпретировать.

Если я использую для l oop получение значений из канала, он работает, как показано ниже.

for i := 0; i < 5; i++ {
    fmt.Println(<-myIntChannel) //receiving value
}

Может кто-нибудь помочь мне понять это концепция

Ответы [ 2 ]

3 голосов
/ 21 марта 2020

for ... range по каналу завершается только после того, как все значения были получены от канала, и канал был закрыт.

В вашем примере вы будете sh, чтобы закрыть канал в отложенной функции, но это будет работать только тогда, когда main() возвращается. Но main() вернется, только если l oop закончится. Это причина тупика. for l oop ожидает закрытия канала, а закрытие канала ожидает окончания l oop.

При использовании al oop для получения в точности 5 значений канал, он работает, потому что запущенные goroutines отправляет на него 5 значений. Этот l oop не ожидает закрытия канала, поэтому l oop может завершиться, как и функция main().

Вот почему sender следует закрыть канал (не приемник), и проблема будет решена немедленно:

func sendValues(myIntChannel chan int) {
    for i := 0; i < 5; i++ {
        myIntChannel <- i //sending value
    }
    close(myIntChannel)
}

func main() {
    myIntChannel := make(chan int)
    go sendValues(myIntChannel)

    for value := range myIntChannel {
        fmt.Println(value) //receiving value
    }
}

Выход (попробуйте на Go Playground ):

0
1
2
3
4
1 голос
/ 21 марта 2020

Чтобы объяснить это немного по-другому, то, что делает ваш код:

func main() {
    ...
    while myIntChannel is not closed {
        ...
    }
    close myIntChannel 
}

Теперь вы можете видеть, откуда возникает тупик.

Хотя приведенный выше ответ действителен, Вы также можете попробовать это, если вы предпочитаете использовать defer:

func sendValues(myIntChannel chan int) {
    defer close(myIntChannel)
    for i := 0; i < 5; i++ {
        myIntChannel <- i //sending value
    }
}

func main() {
    myIntChannel := make(chan int)

    go sendValues(myIntChannel)

    for value := range myIntChannel {
        fmt.Println(value) //receiving value
    }
}
...