Предотвращение тупиков при двунаправленной связи между программами - PullRequest
0 голосов
/ 12 февраля 2019

Я делаю свой первый опыт в го, и до сих пор мне очень нравится конструкция горутин и каналов.Мне интересно, существует ли идиоматический способ избежать тупиков в двунаправленной связи между несколькими программами.Рассмотрим следующий пример.Есть три программы: производитель, рабочий и контроллер .

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

  • Рабочий получает данные от производителя и выполняет с ними определенные операции.Затем работник направляет измененные данные в контроллер.

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

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

producerToWorker := make(chan int)
workerToController := make(chan int)
controllerToWorker := make(chan bool) // bool represents a command for this example

// Worker
go func() {
    for {
        select {
        case i := <-producerToWorker:
            // Do some processing and send to controller
            workerToController <- (2 * i) + 1
        case <-controllerToWorker:
            // Would react to the command here
        }
    }
}()

// Controller
go func() {
    for {
        select {
        case i := <-workerToController:
            fmt.Println(i)
            if i > 180 {
                // Send a command to the worker
                controllerToWorker <- true
            }
        }
    }
}()

// Producer
for {
    producerToWorker <- rand.Intn(100)
}

Пример вывода:

163
175
95
113
1
189 // No deadlock
23
125
179
57
149
23
91
191 // No deadlock
133
95
175
177
181 // No deadlock
17
175
63
27
181 // Deadlock!
fatal error: all goroutines are asleep - deadlock!

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

Edit : Чтобы дать более реальное описание: я столкнулся с этой проблемой, когда пытался реализовать клиент websocket.Клиент веб-сокета ( работник ) подключается к внешней службе ( продюсер ) и получает от нее сообщения ( providerToWorker ) и передает их контроллеру (workerToController ) для обработки полученных сообщений.Контроллер должен реагировать на полученные сообщения, например отправлять ответ или отключать клиента при получении недопустимого сообщения ( controllerToWorker ).

1 Ответ

0 голосов
/ 12 февраля 2019

[Существует ли] идиоматический способ избежать тупиков при двунаправленной связи между несколькими программами?

Нет.Ничего «идиоматического» или основанного на «шаблоне».

Как вы справляетесь с такими ситуациями в Go?

Вы изменяете дизайн.Лучше избегать параллельного кругового потока данных.

...