2013-04-29 20:58 阅读 93


I'm learning Go right now using and one of my first projects is a simple ping script. Essentially I want to ping a bunch of urls, and on response of each one wait XXX number of seconds then ping again. Here is the abridged code:

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

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

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

    //  output logs to the terminal
    //  channel is global
    for i := range c {

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()


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

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

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

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

On my Get request I was previously calling defer res.Body.Close() but that was panicing after the app ran for awhile. I assumed that the defer could not call the Close() on the response until the goroutine had been garbage collected and the res no longer existed.

That got me thinking if by calling a goroutine inside of a goroutine was best practice or if I as causing the function to never exit, and then a defer would only be called once the goroutine was garbage collected.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

2条回答 默认 最新

  • 已采纳
    doujiacai4986 doujiacai4986 2013-04-29 21:21

    That is fine. It's perfectly acceptable to call a goroutine from another goroutine. The calling goroutine will still exit and the new goroutine will go on it's merry way.

    点赞 评论 复制链接分享
  • duanbi3151 duanbi3151 2013-04-29 21:30

    Spaning a new goroutine from within a goroutine is per se perfectly fine.

    But I doubt this is the simplest and cleanest solution to your issue. I guess that your first version did the obvious thing and ping each URL in an endless loop. And this bites defer: Defer'ed calls are executed once the function returns. (This has nothing to do wit a goroutine beeing "garbage collected; actually goroutines just end, the are not collected). In an endless loop you never return, you just accumulate defered calls which get never executed. You thus never close all the open res.Body and you run out of memory/whatever and see a panic.

    Doing defer res.Body.Close is a nice idiom, but not inside an endless loop.

    I would try your first version and directly execute res.Body.Close on the nil error path.

    点赞 评论 复制链接分享