我有这个测试程序将并行获取url,但是当我将并行数增加到大约1040时,我开始出现lookup www.httpbin.org: no such host
错误。
在谷歌之后,我发现其他人说没有关闭响应会导致问题,但我确实用res.Body.Close()
关闭了。
这里有什么问题?非常感谢。
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func get(url string) ([]byte, error) {
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return nil, err
}
bytes, read_err := ioutil.ReadAll(res.Body)
res.Body.Close()
fmt.Println(bytes)
return bytes, read_err
}
func main() {
for i := 0; i < 1040; i++ {
go get(fmt.Sprintf("http://www.httpbin.org/get?a=%d", i))
}
}
答案 0 :(得分:11)
那是因为你的代码中最多可能有1040个并发调用,所以你很可能处于打开1040并且尚未关闭的状态。
您需要限制使用的goroutines数量。
这是一个可能的解决方案,限制为100个并发调用max:
func getThemAll() {
nbConcurrentGet := 100
urls := make(chan string, nbConcurrentGet)
for i := 0; i < nbConcurrentGet; i++ {
go func (){
for url := range urls {
get(url)
}
}()
}
for i:=0; i<1040; i++ {
urls <- fmt.Sprintf("http://www.httpbin.org/get?a=%d", i)
}
}
如果您在程序的main函数中调用它,它可能会在所有任务完成之前停止。您可以使用sync.WaitGroup
来阻止它:
func main() {
nbConcurrentGet := 100
urls := make(chan string, nbConcurrentGet)
var wg sync.WaitGroup
for i := 0; i < nbConcurrentGet; i++ {
go func (){
for url := range urls {
get(url)
wg.Done()
}
}()
}
for i:=0; i<1040; i++ {
wg.Add(1)
urls <- fmt.Sprintf("http://www.httpbin.org/get?a=%d", i)
}
wg.Wait()
fmt.Println("Finished")
}
答案 1 :(得分:11)
从技术上讲,您的过程受限(通过内核)到大约1000个打开的文件描述符。根据具体情况,您可能需要增加此数字。
在你的shell运行中(注意最后一行):
$ ulimit -a
-t: cpu time (seconds) unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) unlimited
-s: stack size (kbytes) 8192
-c: core file size (blocks) 0
-v: address space (kb) unlimited
-l: locked-in-memory size (kb) unlimited
-u: processes 709
-n: file descriptors 2560
增加(临时):
$ ulimit -n 5000
(no output)
然后验证fd限制:
$ ulimit -n
5000