Чтение выходов из двух каналов в цикле навсегда - PullRequest
0 голосов
/ 04 мая 2018

Я работаю над древовидным упражнением tour.golang . Я попытался реализовать ту же функцию, как написано ниже.

func Same(t1, t2 *tree.Tree) bool {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go Walk(t1, ch1);
    go Walk(t2, ch2);

    for c := range ch1 {
        d := <- ch2
        if c-d !=0 {
            return false
        }   

    }
    return true
}

Используя цикл forever, я бы хотел сравнить, если вывод из ch1 отличается от вывода ch2. Но следующее выдает эту ошибку:

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

живая версия

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

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

func WalkTreeAndThenCloseChannel(t *tree.Tree, ch chan int) {
    Walk(t, ch)
    close(ch)
}

func Same(t1, t2 *tree.Tree) bool {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go WalkTreeAndThenCloseChannel(t1, ch1);
    go WalkTreeAndThenCloseChannel(t2, ch2);

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

0 голосов
/ 04 мая 2018

Вы видите тупик по очень простой причине: вы превышаете ch1, но никогда не закрываете его, поэтому цикл for никогда не завершается.

Вы можете исправить это, вручную итерируя по каждому дереву только определенное количество раз, как ваш цикл 0..10 в main():

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go Walk(t1, ch1)
    go Walk(t2, ch2)

    for i := 0; i < 10; i++ {
        c := <-ch1
        d := <-ch2
        if c-d != 0 {
            return false
        }

    }
    return true
}

Детская площадка

Кроме того, вы можете изменить сигнатуру Walk, чтобы она принимала аргумент группы ожидания, который увеличивается вызывающим абонентом Walk и уменьшается, когда каждый Walk возвращается вместе с программой, чтобы закрыть канал после того, как вы закончите прогулку:

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    if t.Left != nil {
        wg.Add(1)
        Walk(t.Left, ch, wg)
    }
    ch <- t.Value
    if t.Right != nil {
        wg.Add(1)
        Walk(t.Right, ch, wg)
    }

}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
    ch1 := make(chan int)
    ch2 := make(chan int)

    var wg1 sync.WaitGroup
    wg1.Add(1)
    go Walk(t1, ch1, &wg1)
    go func() {
        wg1.Wait()
        close(ch1)
    }()

    var wg2 sync.WaitGroup
    wg2.Add(1)
    go Walk(t2, ch2, &wg2)
    go func() {
        // not strictly necessary, since we're not ranging over ch2, but here for completeness
        wg2.Wait()
        close(ch2)
    }()

    for c := range ch1 {
        d := <-ch2
        if c-d != 0 {
            return false
        }

    }
    return true
}

Детская площадка

0 голосов
/ 04 мая 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...