Перейти рабочий процесс, когда только отправка значений на канал - PullRequest
0 голосов
/ 22 мая 2019

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

package main

import "fmt"

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

  fmt.Println("Does not work")
}

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

fatal error: all goroutines are asleep - deadlock! 

Но когда я запускаю следующий код, он не выдает никакой ошибки

package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)

    fmt.Println("did not receive but still works")
}

и отпечатки

did not receive but still works

Я не мог понять, почему это работает во втором случае, пока оно не работает в первом случае. Хотя я не получил никакого значения для канала в обоих случаях. Кроме того, что вызывает тупик в первом случае и как его избежать во втором случае?

1 Ответ

2 голосов
/ 22 мая 2019

Ни один из примеров не работает.На самом деле, ни один пример, который только посылает на канал, никогда не будет работать, в традиционном смысле «работа».

Но вот шаг за шагом, чтобы прояснить:

Первый пример

ch := make(chan int)

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

ch <- 1

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

Второй пример

c := make(chan int)

Снова, создайте небуферизованный канал.

go sum(s[:len(s)/2], c)

Вызовите функцию sum, которая, кстати, также будет блокироваться навсегда по причинам, описанным выше - ничего на канале не принимается, поэтому он будет ждать вечно.Тем не менее, в этом случае вы назвали это в goroutine.Программа будет выполняться в отдельном потоке выполнения, в то время как другие части программы выполняются.Хотя из-за того, что данные с канала никогда не поступают, эта программа никогда не завершится, пока не выйдет основная программа.

go sum(s[len(s)/2:], c)

Снова вы вызываете sum, и снова в программе.Таким образом, на данный момент у вас есть три gorotuines: один работает main(), и один каждый выполняет вызов sum().Последние два никогда не завершатся.

Тогда ваша программа завершится.При выходе из программы все программы (включая две, застрявшие навсегда в ожидании на вашем канале) завершаются.

Поскольку эта программа выходит немедленно, о взаимоблокировке никогда не сообщается, но она наверняка существует, как и в вашейПервый пример.

...