doumen6605 2014-05-10 14:19
浏览 86
已采纳

使用通道超时的golang

I am using goroutines/channels to check if list of urls are reachable. Here is my code. This seems to always return true. Why is the timeout case not getting executed? The goal is to return false even if one of the urls is not reachable

import "fmt"
import "time"

func check(u string) bool {
    time.Sleep(4 * time.Second)
    return true
}

func IsReachable(urls []string) bool {

    ch := make(chan bool, 1)
    for _, url := range urls {
        go func(u string) {
            select {
            case ch <- check(u):
            case <-time.After(time.Second):
                ch<-false
            }
        }(url)
    }
    return <-ch
}
func main() {
    fmt.Println(IsReachable([]string{"url1"}))
}
  • 写回答

4条回答 默认 最新

  • dongzhuo3059 2014-05-10 14:47
    关注

    check(u) will sleep in the current goroutine, i.e. the one that's running func. The select statement is only run properly once it returns, and by that time, both branches are runnable and the runtime can pick whichever one it pleases.

    You can solve it by running check inside yet another goroutine:

    package main
    
    import "fmt"
    import "time"
    
    func check(u string, checked chan<- bool) {
        time.Sleep(4 * time.Second)
        checked <- true
    }
    
    func IsReachable(urls []string) bool {
    
        ch := make(chan bool, 1)
        for _, url := range urls {
            go func(u string) {
                checked := make(chan bool)
                go check(u, checked)
                select {
                case ret := <-checked:
                    ch <- ret
                case <-time.After(1 * time.Second):
                    ch <- false
                }
            }(url)
        }
        return <-ch
    }
    func main() {
        fmt.Println(IsReachable([]string{"url1"}))
    }
    

    It seems you want to check reachability of a set of URLs, and return true if one of them is available. If the timeout is long compared to the time it takes to spin up a goroutine, you could simplify this by having just one timeout for all URLs together. But we need to make sure that the channel is large enough to hold the answers from all checks, or the ones that don't "win" will block forever:

    package main
    
    import "fmt"
    import "time"
    
    func check(u string, ch chan<- bool) {
        time.Sleep(4 * time.Second)
        ch <- true
    }
    
    func IsReachable(urls []string) bool {
        ch := make(chan bool, len(urls))
        for _, url := range urls {
            go check(url, ch)
        }
        time.AfterFunc(time.Second, func() { ch <- false })
        return <-ch
    }
    func main() {
        fmt.Println(IsReachable([]string{"url1", "url2"}))
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失