Golang 程序没有执行完就挂了
Golang program hangs without finishing execution
我有以下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")
}
然而当我运行它;它挂起(即应该打印 Im done
的最后一部分没有 运行。)
这是终端输出;;
$去运行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 已获取}
问题在于,除非通道关闭,否则 for 循环中在通道上的测距将永远持续下去。如果你想从通道中精确读取 len(urls)
值,你应该循环那么多次:
for i := 0; i < len(urls); i++ {
fmt.Println(<-ch)
}
另一个肮脏的狡猾技巧是使用 sync.WaitGroup
并按 goroutine
增加它,然后用 Wait
监控它,完成后它会关闭你的频道允许运行 的下一个代码块,我向您提供这种方法的原因是因为它避免了在 len(urls)
之类的循环中使用静态数字,这样您就可以拥有一个可能会更改的动态切片,并且什么不是。
Wait
和 close
在它们自己的 goroutine 中的原因是您的代码可以通过您的频道
到达 for loop
到 range
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")
}
我有以下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")
}
然而当我运行它;它挂起(即应该打印 Im done
的最后一部分没有 运行。)
这是终端输出;;
$去运行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 已获取}
问题在于,除非通道关闭,否则 for 循环中在通道上的测距将永远持续下去。如果你想从通道中精确读取 len(urls)
值,你应该循环那么多次:
for i := 0; i < len(urls); i++ {
fmt.Println(<-ch)
}
另一个肮脏的狡猾技巧是使用 sync.WaitGroup
并按 goroutine
增加它,然后用 Wait
监控它,完成后它会关闭你的频道允许运行 的下一个代码块,我向您提供这种方法的原因是因为它避免了在 len(urls)
之类的循环中使用静态数字,这样您就可以拥有一个可能会更改的动态切片,并且什么不是。
Wait
和 close
在它们自己的 goroutine 中的原因是您的代码可以通过您的频道
for loop
到 range
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")
}