2014-05-10 60 views
11

我正在使用goroutines /頻道來檢查是否可以到達URL列表。這是我的代碼。這似乎總是返回真實。爲什麼超時情況沒有得到執行?我們的目標是返回false,即使有一個網址無法訪問golang使用頻道超時

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

回答

10

check(u)將在當前睡 goroutine,即正在運行的那個funcselect語句只有在返回時才能正常運行,到那時,兩個分支都可以運行,並且運行時可以選擇任意一個。

您可以通過另一個夠程內運行check解決這個問題:

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

看來要檢查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"})) 
} 
+0

謝謝。實際上,如果其中一個無法訪問,我想返回不可訪問。因此,只有在超時和time.AfterFunc可以在總超時後寫入true時,檢查函數纔會寫入「false」以便通道在通道未能到達url(並且在達到url時不寫入任何內容)。 – Kamal

3

的原因,這總是返回true是要你select聲明中呼籲check(u)。您需要在執行例程中調用它,然後使用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 
    } 
} 

然後從一個循環中調用此函數:

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

Play

0

更改的行

ch := make(chan bool, 1) 

ch := make(chan bool) 

你做一個開放異步(=非阻塞)通道,但你需要一個阻塞通道,以得到它的工作。