我正在检查服务器的状态。服务器的睡眠时间超过15秒,我正在检查超时。
package main
import (
"fmt"
"net/http"
"time"
)
var urls = []string{
"http://site-centos-64:8080/examples/abc1.jsp",
}
type HttpResponse struct {
url string
response *http.Response
err error
}
var ch = make(chan *HttpResponse, 100) // buffered
var count int
func asyncHttpGets(urls []string) []*HttpResponse {
responses := []*HttpResponse{}
count:=0
timeout := make(chan bool, 100)
for i:=0;i<500;i++{
go func(){
for _, url := range urls {
resp, err := http.Get(url)
count++;
go func() {
time.Sleep(1 * time.Second)
timeout <- true
}()
ch <- &HttpResponse{url, resp, err}
if err != nil {
return
}
resp.Body.Close()
}
}()
}
for {
select {
case r := <-ch:
responses = append(responses, r)
if count == 500 {
return responses
}
case <-timeout:
fmt.Println("Timed Out")
if count == 500 {
return responses
}
}
}
return responses
}
func main() {
now:=time.Now()
results := asyncHttpGets(urls)
for _, result := range results {
fmt.Printf("%s status: %s\n", result.url,result.response.Status)
}
fmt.Println( time.Since(now))
}
但正在发生的事情是,它最初打印出“超时”,但最后150-200个请求显示“200 OK”状态,它不应该。此外,当尝试执行1000次时,它显示“恐慌:运行时错误:无效的内存地址或无指针取消引用”
答案 0 :(得分:2)
在启动超时goroutine之前,您正在执行resp, err := http.Get(url)
。
这将导致所有内容阻塞,直到响应准备就绪,然后同时发送两个通道。
只需在发送请求之前将超时goroutine启动到该行,就可以了。即:
for _, url := range urls {
go func() {
time.Sleep(1 * time.Second)
timeout <- true
count++;
}()
resp, err := http.Get(url)
count++; //I think this is what you meant, right?
ch <- &HttpResponse{url, resp, err}
if err != nil {
return
}
resp.Body.Close()
}
BTW尝试使用原子增量进行计数,并且可能使用等待组和time.After
通道而不是睡眠。
答案 1 :(得分:0)
如果您想避免将并发逻辑与业务逻辑混合,我编写了这个库https://github.com/shomali11/parallelizer来帮助您。它封装了并发逻辑,因此您不必担心它。
所以在你的例子中:
package main
import (
"github.com/shomali11/parallelizer"
"fmt"
)
func main() {
urls := []string{ ... }
results = make([]*HttpResponse, len(urls)
options := &Options{ Timeout: time.Second }
group := parallelizer.NewGroup(options)
for index, url := range urls {
group.Add(func(index int, url string, results *[]*HttpResponse) {
return func () {
...
results[index] = &HttpResponse{url, response, err}
}
}(index, url, &results))
}
err := group.Run()
fmt.Println("Done")
fmt.Println(fmt.Sprintf("Results: %v", results))
fmt.Printf("Error: %v", err) // nil if it completed, err if timed out
}