13

URL を並列にフェッチするこのテスト プログラムがありますが、並列数を約 1040 に増やすと、lookup www.httpbin.org: no such hostエラーが発生し始めます。

いくつかのGoogleの後、他の人が応答を閉じないと問題が発生すると言っていることを発見しましたが、私はそれを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個の開いているファイル記述子に制限されています。コンテキストによっては、この数を増やす必要がある場合があります。

シェルランで(最後の行に注意してください):

$ 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 個の本体が開かれ、まだ閉じられていない状態になる可能性が非常に高いためです。

使用するゴルーチンの数を制限する必要があります。

最大同時呼び出し数が 100 に制限されている場合の解決策の 1 つを次に示します。

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)
    }
}

プログラムのメイン関数でこれを呼び出すと、すべてのタスクが完了する前に停止する場合があります。あなたは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")
}
于 2012-10-18T11:10:23.343 に答える