dongmi0760 2016-04-29 15:20
浏览 215
已采纳

Golang为什么这个超时方案不起作用?

So i have this code block for sending a message. The message which gets passed to c.outChan is transmitted and if an ack is recieved in return, a "true" will be passed through the c.buffer[nr].signaler channel. This seems to work fine, but if the message is dropped ( no ack recieved ), instead of reaching the timeout print, it just stoppes, and i don't know why. Here is the code:

func (c *uConnection) send(nr uint32) {
    //transmitt message
    c.outChan <- c.buffer[nr].msg
    timeout := make(chan bool, 1)
    go func() {
        timeoutTimer := time.After(c.retransTime)
        <-timeoutTimer
        timeout <- true
    }()
    switch {
    case <-c.buffer[nr].signaler:
        fmt.Printf("Ack confirmed: %v
", nr)
    case <-timeout:
        fmt.Println("-----------timeout-----------
")
        //resending
        c.send(nr)
    }
}

What am i doing wrong?

  • 写回答

1条回答 默认 最新

  • douzhanhui5662 2016-04-29 15:30
    关注

    You are using a switch for your channels, but you need a select. The switch doesn't know anything about channels and instead just tries to evaluate the expression in the case statements before the select. Your current code is equivalent to this:

    func (c *uConnection) send(nr uint32) {
        //transmitt message
        c.outChan <- c.buffer[nr].msg
        timeout := make(chan bool, 1)
        go func() {
            timeoutTimer := time.After(c.retransTime)
            <-timeoutTimer
            timeout <- true
        }()
        tmp1 := <-c.buffer[nr].signaler // this will block
        tmp2 := <-timeout
        switch {
        case tmp1 :
            fmt.Printf("Ack confirmed: %v
    ", nr)
        case tmp2 :
            fmt.Println("-----------timeout-----------
    ")
            //resending
            c.send(nr)
        }
    }
    

    Your code should look like this (using select instead of switch):

    func (c *uConnection) send(nr uint32) {
        //transmitt message
        c.outChan <- c.buffer[nr].msg
        timeout := make(chan bool, 1)
        go func() {
            timeoutTimer := time.After(c.retransTime)
            <-timeoutTimer
            timeout <- true
        }()
        select {
        case <-c.buffer[nr].signaler:
            fmt.Printf("Ack confirmed: %v
    ", nr)
        case <-timeout:
            fmt.Println("-----------timeout-----------
    ")
            //resending
            c.send(nr)
        }
    }
    

    Also your timeout goroutine is unnecessary. Instead of calling time.After, waiting on the channel and then sending into your own timeout channel you could directly wait on time.After. Example:

    func (c *uConnection) send(nr uint32) {
        //transmitt message
        c.outChan <- c.buffer[nr].msg
        select {
        case <-c.buffer[nr].signaler:
            fmt.Printf("Ack confirmed: %v
    ", nr)
        case <-time.After(c.retransTime):
            fmt.Println("-----------timeout-----------
    ")
            //resending
            c.send(nr)
        }
    }
    

    This is faster, more clear and uses less memory.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 易语言把MYSQL数据库中的数据添加至组合框
  • ¥20 求数据集和代码#有偿答复
  • ¥15 关于下拉菜单选项关联的问题
  • ¥20 java-OJ-健康体检
  • ¥15 rs485的上拉下拉,不会对a-b<-200mv有影响吗,就是接受时,对判断逻辑0有影响吗
  • ¥15 使用phpstudy在云服务器上搭建个人网站
  • ¥15 应该如何判断含间隙的曲柄摇杆机构,轴与轴承是否发生了碰撞?
  • ¥15 vue3+express部署到nginx
  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况