【问题标题】:Golang program hangs without finishing executionGolang程序未完成执行就挂起
【发布时间】:2016-03-10 14:20:04
【问题描述】:

我有以下golang程序;

package main

import (
    "fmt"
    "net/http"
    "time"
)

var urls = []string{
    "http://www.google.com/",
    "http://golang.org/",
    "http://yahoo.com/",
}

type HttpResponse struct {
    url      string
    response *http.Response
    err      error
    status   string
}

func asyncHttpGets(url string, ch chan *HttpResponse) {
    client := http.Client{}
    if url == "http://www.google.com/" {
        time.Sleep(500 * time.Millisecond) //google is down
    }

    fmt.Printf("Fetching %s \n", url)
    resp, err := client.Get(url)
    u := &HttpResponse{url, resp, err, "fetched"}
    ch <- u
    fmt.Println("sent to chan")
}

func main() {
    fmt.Println("start")
    ch := make(chan *HttpResponse, len(urls))
    for _, url := range urls {
        go asyncHttpGets(url, ch)
    }

    for i := range ch {
        fmt.Println(i)
    }
    fmt.Println("Im done")

}

Run it on Playground

但是当我运行它时;它挂起(即应该打印Im done 的最后一部分不运行。) 这是终端输出;;
$ go run get.go
开始
获取http://yahoo.com/
获取http://golang.org/
正在获取http://www.google.com/
发给陈
&{http://www.google.com/ 0xc820144120 已取}
发给陈
&{http://golang.org/ 0xc82008b710 已获取}
发给陈
&{http://yahoo.com/ 0xc82008b7a0 已取}

【问题讨论】:

    标签: go channel goroutine


    【解决方案1】:

    问题在于,除非通道关闭,否则 for 循环中的通道范围将永远持续下去。如果您想从频道中准确读取len(urls) 值,您应该循环多次:

    for i := 0; i < len(urls); i++ {
        fmt.Println(<-ch)
    }
    

    【讨论】:

      【解决方案2】:

      另一个好的肮脏狡猾的技巧是使用sync.WaitGroup 并根据goroutine 递增它,然后使用Wait 对其进行监视,完成后它将关闭您的频道,允许下一个代码块运行,我为您提供这种方法的原因是因为它可以避免在像len(urls) 这样的循环中使用静态数字,这样您就可以拥有一个可能会发生变化的动态切片。

      Waitclose 在它们自己的 goroutine 中的原因是您的代码可以通过您的频道到达 for looprange

      package main
      
      import (
          "fmt"
          "net/http"
          "time"
          "sync"
      )
      
      var urls = []string{
          "http://www.google.com/",
          "http://golang.org/",
          "http://yahoo.com/",
      }
      
      type HttpResponse struct {
          url      string
          response *http.Response
          err      error
          status   string
      }
      
      func asyncHttpGets(url string, ch chan *HttpResponse, wg *sync.WaitGroup) {
          client := http.Client{}
          if url == "http://www.google.com/" {
              time.Sleep(500 * time.Millisecond) //google is down
          }
      
          fmt.Printf("Fetching %s \n", url)
          resp, err := client.Get(url)
          u := &HttpResponse{url, resp, err, "fetched"}
          ch <- u
          fmt.Println("sent to chan")
          wg.Done()
      }
      
      func main() {
          fmt.Println("start")
          ch := make(chan *HttpResponse, len(urls))
          var wg sync.WaitGroup
          for _, url := range urls {
              wg.Add(1)
              go asyncHttpGets(url, ch, &wg)
          }
      
          go func() {
              wg.Wait()
              close(ch)
          }()
      
          for i := range ch {
              fmt.Println(i)
          }
          fmt.Println("Im done")
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-17
        • 1970-01-01
        • 2019-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-12
        • 2011-03-29
        相关资源
        最近更新 更多