Перейти канал готовности - PullRequest
0 голосов
/ 22 мая 2019

Я пытаюсь понять каналы в Go. Я прочитал, что по умолчанию отправляет и получает блок, пока отправитель и получатель не будут готовы. Но как нам выяснить готовность отправителя и получателя.

Например, в следующем коде

package main

import "fmt"

func main() {
    ch := make(chan int)
    ch <- 1

    fmt.Println(<-ch)
}

Программа застрянет на операции отправки канала, ожидая, что кто-то прочтет значение. Несмотря на то, что у нас есть операция приема в выражении println, она заходит в тупик.

Но для следующей программы

package main

import "fmt"

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

    go func () {
        ch <- 1
    }()

    fmt.Println(<-ch)
}

Целочисленное значение успешно передается из подпрограммы go в основную программу. Что заставило эту программу работать? Почему второй работает, а первый нет? Вызывает ли рутина какую-то разницу?

Ответы [ 2 ]

1 голос
/ 22 мая 2019

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

В вашем первом примере единственный поток блокируется оператором записи канала и никогда не достигнет чтения канала.

Вам нужно иметь параллельную подпрограмму go для чтения из канала всякий раз, когда вы пишете в него.Параллельность идет рука об руку с использованием канала.

1 голос
/ 22 мая 2019

Давайте пройдемся по первой программе:

// My notes here
ch := make(chan int)  // make a new int channel
ch <- 1               // block until we can send to that channel
                      // keep blocking
                      // keep blocking
                      // still waiting for a receiver
                      // no reason to stop blocking yet...

// this line is never reached, because it blocks above forever.
fmt.Println(<-ch)

Вторая программа разбивает отправку на собственную строку исполнения, поэтому теперь мы имеем:

ch := make(chan int)  // make a new int channel

go func () {          // start a new line of execution
    ch <- 1           // block this second execution thread until we can send to that channel
}()

fmt.Println(<-ch)     // block the main line of execution until we can read from that channel

Поскольку эти две строки выполнения могут работать независимо, основная строка может опуститься до fmt.Println и попытаться получить канал. Второй поток будет ждать отправки, пока не получит.

...