我正在通过编写一个 HTTP 测试客户端来学习 Go,比如 Apache 的ab. 下面的代码看起来非常简单:我创建了一个可配置数量的 goroutine,每个 goroutine 发送一部分整体 HTTP 请求并记录结果。我遍历resultChan通道并检查/记录每个结果。当消息数量为 100 时,这会起作用。但是,当我增加消息数量时,它会挂起并且 htop 显示该进程的 VIRT 为 138G。这是有问题的代码:package mainimport "net/http"import "fmt"import "time"const ( SUCCESS = iota TOTAL = iota TIMEOUT = iota ERROR = iota)type Result struct { successful int total int timeouts int errors int duration time.Duration}func makeRequests(url string, messages int, resultChan chan<- *http.Response) { for i := 0; i < messages; i++ { resp, _ := http.Get(url) if resp != nil { resultChan <- resp } }}func deployRequests(url string, threads int, messages int) *Result { results := new (Result) resultChan := make(chan *http.Response) start := time.Now() defer func() { fmt.Printf("%s\n", time.Since(start)) }() for i := 0; i < threads; i++ { go makeRequests(url, (messages/threads) + 1, resultChan) } for response := range resultChan { if response.StatusCode != 200 { results.errors += 1 } else { results.successful += 1 } results.total += 1 if results.total == messages { return results } } return results}func main () { results := deployRequests("http://www.google.com", 10, 1000) fmt.Printf("Total: %d\n", results.total) fmt.Printf("Successful: %d\n", results.successful) fmt.Printf("Error: %d\n", results.errors) fmt.Printf("Timeouts: %d\n", results.timeouts) fmt.Printf("%s", results.duration)}显然有一些东西丢失或愚蠢地完成了(没有超时检查,通道是同步的,等等)但我想在修复这些之前让基本案例正常工作。所编写的程序是什么导致如此多的内存分配?据我所知,只有 10 个 goroutine。如果每个 HTTP 请求都创建一个,这是有道理的,如何执行会在循环中创建许多 goroutine 的操作?或者是完全不相关的问题。
1 回答
当年话下
TA贡献1890条经验 获得超9个赞
我认为导致挂起的顺序是:
http.Get
在makeRequests
失败(连接拒绝,请求超时,等等),返回一个nil
响应和误差值错误被忽略并
makeRequests
转移到下一个请求如果发生任何错误,将
makeRequests
少于预期数量的结果发布到resultChan
该
for .. range .. chan
环路deployRequests
从来没有打破,因为results.total
总是小于messages
一种解决方法是:
如果http.Get
返回错误值,请将nil
响应发布到resultChan
:
resp, err := http.Get(url)
if err != nil {
resultChan <- nil
} else if resp != nil {
resultChan <- resp
}
在 中deployRequests,如果for循环从 中读取 nil 值,则将其resultChan计为错误:
for response := range resultChan {
if response == nil {
results.errors += 1
} else if response.StatusCode != 200 {
// ...
- 1 回答
- 0 关注
- 186 浏览
添加回答
举报
0/150
提交
取消