2013-04-29 46 views
6

我正在学习使用,我的第一个项目之一是一个简单的ping脚本。基本上我想ping一堆网址,并在每个人的响应等待XXX秒数然后再次ping。下面是删节代码:在goroutines内部启动goroutines是否可以接受?

func main() { 
    // read our text file of urls 
    f, err := ioutil.ReadFile(urlFile) 
    if err != nil { 
     log.Print(err) 
    } 

    urlStrings := []string{} 
    urlStrings = strings.Split(string(f), "\n") 

    for _, v := range urlStrings { 
     go ping(v) 
    } 

    // output logs to the terminal 
    // channel is global 
    for i := range c { 
     fmt.Println(i) 
    } 
} 

func ping(url string) { 
    // for our lag timer 
    start := time.Now() 

    // make our request 
    _, err := http.Get(url) 

    if err != nil { 
     msg := url + " Error:" + err.Error() 

     fmt.Println(msg) 

     c <- msg 
     reportError(msg) 
    } else { 
     lag := time.Since(start) 
     var msg string 

     // running slow 
     if lag > lagThreshold*time.Second { 
      msg = url + " lag: " + lag.String() 
      reportError(msg) 
     } 

     msg = url + ", lag: " + lag.String() 
     c <- msg 
    } 

    time.Sleep(pingInterval * time.Second) 
    go ping(url) // is this acceptable? 
} 

在我的Get请求我以前呼吁推迟res.Body.Close(),但是这是panicing后的应用程序运行一段时间。我认为延迟无法在响应中调用Close(),直到goroutine被垃圾收集并且res不再存在。

这让我想到如果通过调用goroutine内部的goroutine是最佳做法,或者如果我导致函数永不退出,那么只有在goroutine被垃圾收集后才会调用延迟。

+0

从其他goroutines产生goroutines应该没有任何问题,但是有什么理由不在这种情况下使用循环吗? – 2013-04-29 21:28:12

+0

@JamesHenstridge I在程序循环中没有这样做,所以我不必在每次请求返回之前等待每个请求返回。我试图使用并发性,因此每个ping周期都是基于它自己的滞后时间而独立的。 – ARolek 2013-04-29 22:52:50

+0

我指的是'ping()'goroutine在退出前产生另一个goroutine的部分。如果你在'ping()'中放置一个循环,你会得到同样的效果。 – 2013-04-29 23:26:21

回答

11

这很好。从另一个goroutine调用goroutine是完全可以接受的。调用的goroutine将会退出,新的goroutine将继续进行。

7

从goroutine内部新建一个goroutine本身就非常好。

但我怀疑这是对您的问题最简单和最干净的解决方案。 我想你的第一个版本做了明显的事情,并在无尽的循环中ping每个URL。而且这个叮咬推迟:当功能返回时,延迟呼叫被执行。 (这与一个goroutine beeing没有任何关系,“垃圾收集,实际上goroutines刚刚结束,没有收集)。在一个永无止境的循环中,你永远不会回来,你只积累那些永不执行的守卫的召唤。 res.Body你耗尽内存/什么,看到了恐慌。

defer res.Body.Close是一个很好的习惯用法,但不是一个死循环中。

我会尝试你的第一个版本,并直接执行res.Body 。关闭nil错误路径

+0

如果我不调用res.Body.Close()也会使用内存使用情况,或者将res放弃? – ARolek 2013-04-29 22:54:38

+0

您**必须**致电res.Body.Close。由于某种原因记录在案。 (否则你的代码会泄漏。) – Volker 2013-04-30 07:40:27

+0

如果我没有把它当作我以上所做的var来处理,该怎么办? _,err:= http.Get(url)会泄露吗? – ARolek 2013-04-30 17:34:56