3 回答
TA贡献1848条经验 获得超2个赞
这里的第一个问题是在发生错误的情况下您不会返回响应,因此len(responses) == len(urls)很可能永远不会匹配,从而迫使您的循环永远继续下去。
首先sync.WaitGroup为并发请求添加一个
var wg sync.WaitGroup
ch := make(chan *HttpResponse)
responses := []*HttpResponse{}
for _, url := range urls {
wg.Add(1)
go func(url string) {
defer wg.Done()
然后你可以覆盖响应,直到所有未完成的 goroutine 都完成
go func() {
wg.Wait()
close(ch)
}()
for r := range ch {
fmt.Printf("%s was fetched\n", r.url)
responses = append(responses, r)
}
return responses
然后,您必须决定如何处理响应,您是要在并发调用中读取它们,还是返回它们的正文未读。由于如果您想重用连接,您将始终Body.Close()尝试使用主体,并且由于您已经推迟了,因此目前需要在同一个函数调用中发生。您可以更改httpResponse类型以使其成为可能,或者将 替换为resp.Body包含响应的缓冲区。
最后,您将希望为客户端设置某种超时(可能使用 a Context),并对发出的并发请求数进行限制。
TA贡献1878条经验 获得超4个赞
问题是您在没有写入通道的情况下返回错误。看你的if err != nil { return }说法。因为你不写信给频道,所以len(responses) == len(urls)声明永远不会是真的。
go func(url string) {
fmt.Printf("Fetching %s \n", url)
resp, err := http.Get("http://" + url)
if err != nil {
fmt.Printf("Failed to fetch %s\n", err)
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
fmt.Printf("HTTP Response Status : %v", resp.StatusCode)
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
bodyString := string(bodyBytes)
fmt.Printf("HTTP Response Content Length : %v\n", len(bodyString))
}
ch <- &HttpResponse{url, resp, err}
}(url)
TA贡献1868条经验 获得超4个赞
您可以使用以下库:
Requests:一个 Go 库,用于减少发出 HTTP 请求时的麻烦(20k/s req)
https://github.com/alessiosavi/Requests
它是为解决to many open files处理并行请求而开发的。
这个想法是分配一个请求列表,而不是使用可配置的“并行”因子发送它们,该因子允许一次只运行“N”个请求。
初始化请求(你已经有一组 url)
// This array will contains the list of request
var reqs []requests.Request
// N is the number of request to run in parallel, in order to avoid "TO MANY OPEN FILES. N have to be lower than ulimit threshold"
var N int = 12
// Create the list of request
for i := 0; i < 1000; i++ {
// In this case, we init 1000 request with same URL,METHOD,BODY,HEADERS
req, err := requests.InitRequest("https://127.0.0.1:5000", "GET", nil, nil, true)
if err != nil {
// Request is not compliant, and will not be add to the list
log.Println("Skipping request [", i, "]. Error: ", err)
} else {
// If no error occurs, we can append the request created to the list of request that we need to send
reqs = append(reqs, *req)
}
}
此时,我们有一个列表,其中包含必须发送的请求。让我们并行发送它们!
// This array will contains the response from the givens request
var response []datastructure.Response
// send the request using N request to send in parallel
response = requests.ParallelRequest(reqs, N)
// Print the response
for i := range response {
// Dump is a method that print every information related to the response
log.Println("Request [", i, "] -> ", response[i].Dump())
// Or use the data present in the response
log.Println("Headers: ", response[i].Headers)
log.Println("Status code: ", response[i].StatusCode)
log.Println("Time elapsed: ", response[i].Time)
log.Println("Error: ", response[i].Error)
log.Println("Body: ", string(response[i].Body))
}
您可以在存储库的示例文件夹中找到示例用法。
- 3 回答
- 0 关注
- 128 浏览
添加回答
举报
