13

我有这个测试程序,它将并行获取 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))
    }
}
4

2 回答 2

15

从技术上讲,您的进程(受内核)限制为大约 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
于 2012-10-18T15:21:57.433 回答
11

那是因为您的代码中可能有多达 1040 个并发调用,因此您很可能处于打开 1040 个主体但尚未关闭的状态。

您需要限制使用的 goroutine 的数量。

这是一种可能的解决方案,最大并发调用数限制为 100:

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 函数中调用它,它可能会在所有任务完成之前停止。您可以使用 async.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")
}
于 2012-10-18T11:10:23.343 回答