golang使用频道超时

Kam*_*mal 15 go channels

我正在使用goroutines/channels来检查网址列表是否可以访问.这是我的代码.这似乎总是回归真实.为什么超时案例没有被执行?即使其中一个网址无法访问,目标也是返回false

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"}))
}
Run Code Online (Sandbox Code Playgroud)

Tho*_*mas 12

check(u)将睡在当前的 goroutine中,即正在运行的那个func.该select语句只有在返回后才能正常运行,到那时,两个分支都是可运行的,运行时可以选择任何一个分支.

您可以通过check在另一个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"}))
}
Run Code Online (Sandbox Code Playgroud)

您似乎想要检查一组URL的可访问性,如果其中一个URL可用,则返回true.如果超时与旋转goroutine所需的时间相比较长,则可以通过将所有URL一起超时一次来简化此操作.但我们需要确保频道足够大以容纳所有支票的答案,否则那些不"赢"的频道将永远阻止:

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"}))
}
Run Code Online (Sandbox Code Playgroud)


Seb*_*ian 5

这始终返回true,原因是你在呼唤check(u)你的内select声明。您需要在go例程中调用它,然后使用select等待结果或超时。

如果要并行检查多个URL的可及性,则需要重组代码。

首先创建一个函数来检查一个URL的可达性:

func IsReachable(url string) bool {
    ch := make(chan bool, 1)
    go func() { ch <- check(url) }()
    select {
    case reachable := <-ch:
        return reachable
    case <-time.After(time.Second):
        // call timed out
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

然后从循环调用此函数:

urls := []string{"url1", "url2", "url3"}
for _, url := range urls {
    go func() { fmt.Println(IsReachable(url)) }()
}
Run Code Online (Sandbox Code Playgroud)