Почему у меня тупик, хотя он включает в себя бесконечный цикл? - PullRequest
0 голосов
/ 12 декабря 2018

Итак, я начал возиться с го, и я очарован рутиной го.Теперь я написал простой тест, чтобы посмотреть, смогу ли я изменить значение переменной, пока я ее непрерывно распечатываю.

Теперь у меня есть следующий код:

package main

import (
    "fmt"
    "time"
)

func change(c chan float64) float64 {
    time.Sleep(2 * time.Second)
    return 2.5
}

func main() {

    s := 1.1

    c := make(chan float64)
    go change(c)
    s = <-c

    for {
        fmt.Println(s)
        time.Sleep(100 * time.Millisecond)
    }    
}

К сожалению, это заканчивается ошибкой:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
        /home/kramer65/repos/go/src/messing_around/main.go:19 +0x7d
exit status 2

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

Может ли кто-нибудь просветить меня, что не так с этим кодом, и как я могу изменить значение переменной, покаЯ постоянно это распечатываю?Все советы приветствуются!

1 Ответ

0 голосов
/ 12 декабря 2018

Похоже, что у вас может быть недопонимание по каналам и процедурам перехода.

Строка:

go change(c)

, кажется, указывает на то, что функция change собирается записать c.Однако в конечном итоге он просто возвращает значение через определенный промежуток времени.

Это значение (2.5) нигде не принимается.Кроме того, c нигде не записывается.Я подозреваю, что вы намеревались записать 2.5 на канал c.Синтаксис для этого следующий:

c<-2.5

Поэтому, если вы измените свою функцию change на:

func change(c chan float64) {
    time.Sleep(2 * time.Second)
    c <- 2.5
}

Вы больше не должны видеть тупик.Обратите внимание, что я больше не возвращаю float64.

Я создал игровую площадку для этого: https://play.golang.org/p/SgLiUmPpcAZ

Обновление для комментариев

1.1 всегда будет перезаписываться значением канала.Однако, если вы хотите напечатать начальное значение s (как указано в комментарии), вам придется немного изменить поток и использовать выражение select:

package main

import (
    "fmt"
    "time"
)

func change(c chan float64) {
    time.Sleep(2 * time.Second)
    c <- 2.5
}

func main() {

    s := 1.1

    c := make(chan float64)
    go change(c)

    for {
        select {
        case s = <-c:
        default:
            // c isn't ready yet
        }
        fmt.Println(s)
        time.Sleep(100 * time.Millisecond)
    }
}

Теперь, когда выесть оператор select, вы также можете использовать его с time.Ticker:

ticker := time.NewTicker(100 * time.Millisecond)
for {
    select {
    case s = <-c:
    case <-ticker.C:
        fmt.Println(s)
    default:
        // c isn't ready yet
    }
}
...