避免goroutine之间的双向通信中的死锁

时间:2019-02-12 14:26:30

标签: go deadlock goroutine channels

我正在Go中进行初次体验,到目前为止,我真的很喜欢goroutine和channel结构。我想知道是否有一种惯用的方法来避免多个goroutine之间的双向通信中的死锁。考虑以下示例。共有三个goroutine:<生产者,工人和<生产者>控制器。

  • 生产者产生整数。实际上这可能是数据的到来 例如通过网络连接。

  • 工作者从生产者那里接收数据,并对其进行一些操作 它。然后,工作人员将修改后的数据定向到控制器。

  • 在某些情况下,控制器会向工作人员发送命令。在里面 例如,如果接收到的整数大于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中处理此类情况?

编辑:给出更真实的描述:当我尝试实现Websocket客户端时遇到了这个问题。 WebSocket客户端( worker )连接到外部服务( producer ),并从外部服务( producerToWorker )接收消息,并将它们传递给控制器​​( workerToController )来处理收到的消息。控制器需要对收到的消息做出反应,例如,当收到无效消息( controllerToWorker )时发送响应或断开客户端连接。

1 个答案:

答案 0 :(得分:1)

  

[有没有一种惯用的方法来避免多个goroutine之间的双向通信中的死锁?

不。没有“惯用的”或基于“模式”的。

  

您如何在Go中处理此类情况?

您重新设计。最好避免并行循环数据流。