简体   繁体   English

Go 中的超时和无缓冲通道迭代

[英]Timeout and Iterating Over Unbuffered Channel in Go

In my code I have a connected graph of nodes, (all nodes are connected to each other directly or indirectly).在我的代码中,我有一个连接的节点图(所有节点都直接或间接地相互连接)。 Upon initialisation each node has a Value which is a random 64 bit integer.初始化后,每个节点都有一个随机 64 位 integer 的Value

type Node struct {
    ID *uuid.UUID

    Value int64

    ListenChannel chan Message

    Connections map[uuid.UUID]*Node
}


type Message struct {
    Value int64
}

The idea is that they will communicate with each other and come to consensus about what is the largest Value .这个想法是他们将相互沟通并就最大的Value达成共识。 (Communication happens over the ListenChannel that each node has, also nodes are modeled as goroutines) (通信发生在每个节点拥有的ListenChannel上,节点也被建模为 goroutines)

func (node *Node) FormConsensus(wg *sync.WaitGroup, retChannel chan int64) {
    defer wg.Done()
    defer func() {
        // this will be a non-blocking operation since the channel is buffered
        retChannel <- node.Value
    }()

    listenWg := sync.WaitGroup{}

    listenWg.Add(1)
    // Add logic to pass messages to and fro and find the maximum value from the network
    go func() {
        for timedOut := false; !timedOut; {
            select {
            case receivedMessage := <-node.ListenChannel:
                if receivedMessage.Value > node.Value {
                    fmt.Println("Received value")
                    node.Value = receivedMessage.Value
                    fmt.Println("Received large value")
                    node.BroadcastValue()
                }
            case <-time.After(5 * time.Second):
                fmt.Println("Timeout")
                listenWg.Done()
                close(node.ListenChannel)
                timedOut = true
            }
        }
    }()

    node.BroadcastValue()
    listenWg.Wait()
}

func (node *Node) BroadcastValue() {
    fmt.Println("broadcasting", node.Value)
    for _, connection := range node.Connections {
        connection.ListenChannel <- Message{node.Value}
    }
}

To achieve this, every node first broadcasts its value to its connections, and also has a goroutine which continuously listens on its own listenChannel for values that other nodes are sending.为实现这一点,每个节点首先将其值广播到其连接,并且还有一个 goroutine,该 goroutine 在其自己的 listenChannel 上持续监听其他节点发送的值。 If the received values are larger than its own, then it updates its own value, and broadcasts the updated value.如果接收到的值大于自己的值,则它会更新自己的值,并广播更新后的值。

With the timeout logic inside the switch case, I am trying to set a 5 second timout, ie, if no messages are received on the channel for 5 seconds, then assume consesus has been reached and exit.使用 switch case 中的超时逻辑,我试图设置 5 秒的超时,即,如果 5 秒内通道上没有收到任何消息,则假设已达成共识并退出。

However on executing the FormConsensus function, it never exits.然而,在执行 FormConsensus function 时,它永远不会退出。 I am not sure where I am going wrong, and as I am very new to Go, I might be doing things which are completely unidiomatic.我不确定哪里出错了,因为我是 Go 的新手,我可能会做一些完全不合常理的事情。 Other than understanding what is going wrong, it would be also very helpful to understand if there is better way to achieve what I am trying to in Go.除了了解出了什么问题,了解是否有更好的方法来实现我在 Go 中尝试的目标也很有帮助。

I'm pretty sure the error is here.我很确定错误就在这里。

func (node *Node) BroadcastValue() {
fmt.Println("broadcasting", node.Value)
for _, connection := range node.Connections {
    select {
    case connection.ListenChannel <- Message{node.Value}:
        fmt.Println("--test message written")
    default:
        fmt.Println("--test message dropped")
    }
}

} }

It looks like the channel write operation is blocking because the buffer is full.看起来通道写入操作正在阻塞,因为缓冲区已满。 You will have to investigate why it is sending more messages than you expect.您将不得不调查为什么它发送的消息比您预期的多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM