繁体   English   中英

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

[英]Timeout and Iterating Over Unbuffered Channel in Go

在我的代码中,我有一个连接的节点图(所有节点都直接或间接地相互连接)。 初始化后,每个节点都有一个随机 64 位 integer 的Value

type Node struct {
    ID *uuid.UUID

    Value int64

    ListenChannel chan Message

    Connections map[uuid.UUID]*Node
}


type Message struct {
    Value int64
}

这个想法是他们将相互沟通并就最大的Value达成共识。 (通信发生在每个节点拥有的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}
    }
}

为实现这一点,每个节点首先将其值广播到其连接,并且还有一个 goroutine,该 goroutine 在其自己的 listenChannel 上持续监听其他节点发送的值。 如果接收到的值大于自己的值,则它会更新自己的值,并广播更新后的值。

使用 switch case 中的超时逻辑,我试图设置 5 秒的超时,即,如果 5 秒内通道上没有收到任何消息,则假设已达成共识并退出。

然而,在执行 FormConsensus function 时,它永远不会退出。 我不确定哪里出错了,因为我是 Go 的新手,我可能会做一些完全不合常理的事情。 除了了解出了什么问题,了解是否有更好的方法来实现我在 Go 中尝试的目标也很有帮助。

我很确定错误就在这里。

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")
    }
}

}

看起来通道写入操作正在阻塞,因为缓冲区已满。 您将不得不调查为什么它发送的消息比您预期的多。

暂无
暂无

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

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