Тупик при порождении горутина в цикле

Рассмотрим следующую игровую площадку

package main

import "fmt"

func main() {

    var chan_array [2]chan int

    chan1 := make(chan int)
    chan2 := make(chan int)

    chan_array[0] = chan1
    chan_array[1] = chan2


    for i := 0; i < 2; i++ {
        go func() {

            select {
                case x := <- chan_array[i]:
                    if (x == 0) {
                        return
                    }       
                    fmt.Println(x)
            }
        }()
    }

    chan1<- 1
    chan2<- 2
    chan1<- 0
    chan2<- 0
}

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

Но приведенный выше код работает в тупик.

Я не совсем уверен, почему

Может кто-нибудь указать на мою ошибку?

Спасибо

2 ответа

Решение

Есть некоторые проблемы:
Какова стоимость i когда chan_array[i-1] работает:

for i := 0; i < 2; i++ {
    go func() {
        select {
        case x := <- chan_array[i-1]:
            if x == 0 {
                return
            }
            fmt.Println(x)
        }
    }()
}

попробуй это:

for i := 0; i < 2; i++ {
    go func(i int) { 
        select {
        case x := <-chan_array[i]:
            if x == 0 {
                return
            }
            fmt.Println(x)
        }
    }(i)
}

Давайте упростим ваш код (с некоторыми исправлениями):

package main

import "fmt"

func main() {
    chan1 := make(chan int)
    chan2 := make(chan int)

    go routine(chan1)
    go routine(chan2)

    chan1 <- 1
    chan2 <- 2
    chan1 <- 0
    chan2 <- 0
}

func routine(ch chan int) {
    select {
    case x := <-ch:
        if x == 0 {
            return
        }
        fmt.Println(x)
    }
}

С этими:

chan1 <- 1
chan2 <- 2

фатальная ошибка:

all goroutines are asleep - deadlock!

твои горутины закончились и никаких гурутин не слушали chan1 а также chan1 Вот:

chan1 <- 0
chan2 <- 0

Ваш исправленный рабочий пример кода:

package main

import "fmt"

func main() {
    chan1 := make(chan int)
    chan2 := make(chan int)

    go routine(chan1)
    go routine(chan2)

    chan1 <- 1
    chan2 <- 2
    chan1 <- 0
    chan2 <- 0
}

func routine(ch chan int) {
    for {
        select {
        case x := <-ch:
            if x == 0 {
                return
            }
            fmt.Println(x)
        }
    }
}

выход:

1
2

К тому времени, как goroutines запускают переменную i уже увеличился. Вместо этого передайте его как параметр функции.

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

Другие вопросы по тегам