Сравнение по ключевому слову "идти" и без в Goroutine - PullRequest
0 голосов
/ 22 марта 2019

Следующий код зарегистрировал ошибку:

фатальная ошибка: все программы спят - тупик!

package main

import "fmt"

func main() {
    ch := make(chan int)
    ch <- 1
    fmt.Println(<-ch)
}

Но когда я изменил код на это:

package main

import "fmt"

func assign (ch chan int) {
    ch <- 1
}

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

    fmt.Println(<-ch)
}

"1" был распечатан.

Затем я использовал буферизованные каналы:

package main

import "fmt"

func main() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

«1» и «2» также могут быть распечатаны.

Я немного запутался в ситуации.Заранее спасибо!

Ответы [ 2 ]

5 голосов
/ 22 марта 2019

Почему произошла тупиковая ситуация:

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

ch <- 1

Поскольку никто не читает с канала, и основная программа ожидает его продолжения.

См. Эффективное начало -> Каналы

Есликанал небуферизован, отправитель блокируется, пока получатель не получит значение.

Функция отправителя main, функция получателя main.

Как избежать тупика:

Чтобы решить эту проблему, у вас есть две опции:

Опция 1: сделать канал ch буферизованным так:

ch := make(chan int, 1) // buffer length is set to 1

From ATour of Go

Отправка в буферный блок канала только при заполненном буфере.

Таким образом, вы можете записывать в канал, пока буфер не заполнится,Затем кто-то должен начать чтение с канала.

Вариант 2: записать в канал из программы, как вы делали во втором фрагменте кода:

func assign(ch chan int) {
    ch <- 1
}

func main() {
    ch := make(chan int)
    go assign(ch) // does not block the main goroutine
    fmt.Println(<-ch) // waiting to read from the channel
}

В этом случае функция main будет выполняться до fmt.Println(<-ch) и продолжится, как только сможет считывать данные с канала.

1 голос
/ 23 марта 2019

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

ch <- 1

Никто еще не читает с канала.Основная процедура заблокирована, и эта строка никогда не выполняется:

fmt.Println(<-ch)

Вот почему вы получили ошибку взаимоблокировки.

Во втором примере вы все еще используете небуферизованный канал, что означаетОперация записи блокирует выполнение программы.Но, используя go, вы запускаете вторую программу.Это означает, что даже если эта новая программа будет заблокирована во время записи (в вашей функции assign), основная программа будет продолжать работать, и fmt.Println(<-ch) будет выполнена и выполнит чтение (что, в свою очередь, разблокирует фоновую программу и assignфункция, наконец, достигнет конца).

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

package main

import "fmt"

func print(ch chan int) {
    fmt.Println(<-ch)
}

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

Когда вы работаетес буферизованным каналом (третий фрагмент) вы можете выполнять операции записи N без блокировки процедуры (где N - размер буфера).Вот почему в вашем примере вы сделали 2 записи без блокировки и можете прочитать их позже.Но если ваш буфер меньше, чем количество операций записи, и никто не выполняет чтение, вы попадете в те же проблемы с блокировкой (см. Объяснение фрагментов 1 и 2).

...