Небуферизованный канал в Go

Pauli спросил: 28 марта 2018 в 03:20 в: go

Вот простой пример кода о небуферизованных каналах:

ch01 := make(chan string)go func() {
    fmt.Println("We are in the sub goroutine")
    fmt.Println(<-ch01)
}()fmt.Println("We are in the main goroutine")
ch01 <- "Hello"

Результат:

We are in the main goroutine 
We are in the sub goroutine 
Hello

Перейти на площадку: https ://play.golang.org/p/rFWQbwXRzGw

По моему мнению, операция отправки заблокировала главный goroutine, пока субрутин не выполнил операцию приема на канале ch01. Затем программа вышла.

После размещения подгорта после операции отправки вроде этого:

fmt.Println("We are in the main goroutine")
ch01 <- "Hello"go func() {
    fmt.Println("We are in the sub goroutine")
    fmt.Println(<-ch01)
}()

Произошел тупик:

We are in the main goroutine
fatal error: all goroutines are asleep - deadlock!

go playgroundhttps://play.golang.org/p/DmRUiBG4UmZ

Что произошло на этот раз? Означает ли это, что после ch01 <- "Hello" главный goroutine был немедленно заблокирован, так что у sub goroutine не было возможности запустить? Если это так, как я должен понимать результат первого примера кода? (Сначала в главном goroutine, затем в sub goroutine).


4 ответа

Есть решение
sberry ответил: 28 марта 2018 в 03:58

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

Во втором примере отправка происходит до того, как получатель готов, поэтому блокировка отправки и взаимоблокировки программы .

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

Maruf Tuhin ответил: 28 марта 2018 в 04:02

Прежде всего, go-routines выполняется одновременно. В первом примере подпрограмма уже запущена, но во втором примере подпрограмма go еще не началась, когда появляется операция отправки.

Подумайте о построчно.

В 1-м примере sub-goroutine запускался одновременно до того, как операция send появилась в основной подпрограмме go. В результате, когда происходит операция отправки, уже существует получатель (sub-goroutine).

Если вы настроите первый пример,

package mainimport (
    "fmt"
    "time"
)func main() {
    ch01 := make(chan string)    go func() {
        fmt.Println("We are in the sub goroutine")
        fmt.Println(<-ch01)
    }()    // wait for start of sub-routine
    time.Sleep(time.Second * 2)    fmt.Println("We are in the main goroutine")
    ch01 <- "Hello"    // wait for the routine to receive and print the string
    time.Sleep(time.Second * 2)}

Вывод будет

We are in the sub goroutine
We are in the main goroutine
Hello

Итак, вы можете видеть, что подпрограмма уже запущена и ожидает получения на канале. Когда основная программа отправляет строку в канал, подпрограмма возобновляет работу и получает сигнал.

Но во 2-м примере программа застряла в основной процедуре go send operation, и подпрограмма Процедура go еще не началась и не запустится, потому что программа еще не получила эту строку. поэтому нет другого приемника для получения сигнала. Так что программа застряла в тупике.

Himanshu ответил: 28 марта 2018 в 05:39

Для небуферизованных каналов подпрограмма go блокируется до тех пор, пока никто не получит ее. Сначала должна быть процедура go для получения значения из канала, а затем отправляется значение в канал. В примере, когда мы отправляем значение в канал, необходимо создать буферизованный канал, чтобы значение сохранялось в буферизованном виде, пока не будет никого, кто получит его, как это будет работать.

package mainimport (
    "fmt"
    "time"
)func main() {
    ch01 := make(chan string, 10)
    ch01 <- "Hello"
    go func() {
        fmt.Println("We are in the sub goroutine")
        fmt.Println(<-ch01)
    }()    fmt.Println("We are in the main goroutine")
    time.Sleep(1 * time.Second)
}
площадка
Uvelichitel ответил: 28 марта 2018 в 05:55

Означало ли это, что после ch01 < -"Hello" основная программа была немедленно заблокирована, чтобы у подпрограммы не было возможности запустить? Если это правда, как я должен понимать результат первого примера кода? (Сначала в основной процедуре, затем в подпрограмме).

Это правда. Вы понимаете, вещи пишите. Порядок оценки порожденных горутин не определен и может контролироваться только с помощью инструментов синхронизации (каналов, мьютексов). Подпрограмма в первом примере может также Print () сначала в другой среде. Это просто не указано .