Все горутины спят - тупик! ------- Ошибка - PullRequest
3 голосов
/ 23 ноября 2011

Я хочу написать три параллельные процедуры go, которые посылают друг другу целые числа. Теперь мой код скомпилирован правильно, однако после первого выполнения он выдает ошибку «все программы спят - тупик!». Я пытался найти ошибку, но не смог найти ошибку в логике кода. Кто-нибудь может мне помочь найти ошибку с моим кодом. Мой код приведен ниже. Заранее спасибо.

package main

import "rand"

func Routine1(command12 chan int, response12 chan int, command13 chan int, response13 chan int) {
    for i := 0; i < 10; i++ {
        y := rand.Intn(10)
        if y%2 == 0 {
            command12 <- y
        }

        if y%2 != 0 {
            command13 <- y
        }
        select {
        case cmd1 := <-response12:
            print(cmd1, " 1st\n")
        case cmd2 := <-response13:
            print(cmd2, " 1st\n")
        }
    }
    close(command12)
}

func Routine2(command12 chan int, response12 chan int, command23 chan int, response23 chan int) {
    for i := 0; i < 10; i++ {
        select {
        case x, open := <-command12:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }

        case x, open := <-response23:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        }

        y := rand.Intn(10)
        if y%2 == 0 {
            response12 <- y
        }

        if y%2 != 0 {
            command23 <- y
        }

    }
}

func Routine3(command13 chan int, response13 chan int, command23 chan int, response23 chan int) {
    for i := 0; i < 10; i++ {
        select {
        case x, open := <-command13:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        case x, open := <-command23:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        }

        y := rand.Intn(10)
        if y%2 == 0 {
            response13 <- y
        }

        if y%2 != 0 {
            response23 <- y
        }

    }
}

func main() {
    command12 := make(chan int)
    response12 := make(chan int)
    command13 := make(chan int)
    response13 := make(chan int)
    command23 := make(chan int)
    response23 := make(chan int)

    go Routine1(command12, response12, command13, response13)
    go Routine2(command12, response12, command23, response23)
    Routine3(command13, response13, command23, response23)
}

Может кто-нибудь сообщить мне, почему, если я объявляю Routine2 и Routine3 как подпрограмму go, почему вывод [нет вывода]. Я новичок в GO и, как я понял из "http://golang.org/doc/effective_go.html#concurrency", go используется для выполнения подпрограмм параллельно с другими подпрограммами в том же адресном пространстве. Итак, в чем проблема, что все подпрограммы работают, но вывод [без вывода].

Чтобы сделать программу более понятной: на самом деле я утомляюсь созданием двух каналов между каждыми двумя подпрограммами, а затем использую один канал для отправки int на другой канал и получения int другим каналом из этой подпрограммы. Например, между подпрограммами 1 и 3 каналов находятся команда 13 и ответ 13. подпрограмма 1 использует команду 13 для отправки int и response13 для получения int в / из подпрограммы 3. Для подпрограммы 3 response13 используется для отправки int и command13 для получения int в / из подпрограммы 1 (команда / response 13 представляет канал между подпрограммой 1 и 3). Теперь, когда три подпрограммы являются параллельными и имеют специальные подпрограммы для обработки полученных сообщений или отправки сообщений, почему они переходят в тупик?

Ответы [ 2 ]

8 голосов
/ 23 ноября 2011
go Routine1(command12, response12,command13, response13 )
go Routine2(command12, response12,command23, response23) // go routine
Routine3(command12, response12,command23, response23 )

Это запустит Routine1 в новой goroutine, а основная goroutine продолжится со следующего оператора.Следовательно, Рутина1 и Рутина2 будут выполняться одновременно, но Рутина3 будет запущена после завершения Рутины2.Вы можете пропустить еще одно утверждение "go" здесь.

Затем я пытался следовать вашей программе.В Routine1 вы делаете

command13 <- y

. Это блокирует Routine1, пока не будет готова другая программа, которая сможет принять ваше сообщение.Поэтому вам нужно y := <-command13 в другой программе.

Но теперь давайте внимательно рассмотрим параметры двух других программ:

Routine2(command12, response12,command23, response23)
Routine3(command12, response12,command23, response23 )

Как вы видите, ни одна из программимеет доступ к команде 13 (но вы передаете команду 12 дважды).Таким образом, ни Routine1, ни Routine2, ни Routine3 не могут продолжить.Тупик!

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

В настоящий момент действительно сложно отладить вашу программу,

  • Я не знаю, что вы пытаетесь сделать.Нет подробного описания потока сообщений или чего-либо подобного.Фактически, ваш код вообще не содержит никакой документации.
  • Вы передаете каналы, которые называются response23, параметру response13 и так далее.Смешать их довольно легко.
  • Все эти родовые имена, такие как command12 и т. Д., Затрудняют понимание того, что этот канал должен делать
  • Хорошая идея gofmt вашего источникакод перед публикацией:)

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

3 голосов
/ 23 ноября 2011

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

Например, в Routine1, если вы позвоните command12 <- y, эта программа будет блокироваться, пока что-то еще не вытянет y из канала. То же самое для command13. Поскольку вы запускаете эти посылки в цикле, а Routine2 и Routine3 работают синхронно, вы сталкиваетесь с проблемой взаимоблокировки.

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

Если Routine2 и Routine3 также являются goroutines, то ничто не мешает вашей программе завершиться - поэтому в этом случае вы ничего не получите.

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

...