亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在 N > 10 URLS 的情況下發送 N 個獲取請求

如何在 N > 10 URLS 的情況下發送 N 個獲取請求

Go
大話西游666 2022-05-18 09:36:35
我正在嘗試發出 N 個獲取請求,但我的代碼適用于 8 個 URL,但 10 個始終堆疊沒有問題。我是 GO 新手,所以我無法理解這個問題。我正在嘗試編寫一個應用程序來擊敗具有相同任務的 .NET 應用程序。你能提出什么問題嗎?package mainimport (    "fmt"    "io/ioutil"    "log"    "net/http"    "os"    //"bufio"    "time")type HttpResponse struct {    url      string    response *http.Response    err      error}func main() {    fmt.Println("Hello, world3.")    var urls []string = []string{    "www.webmagnat.ro",    "nickelfreesolutions.com",    "scheepvaarttelefoongids.nl",    "tursan.net",    "plannersanonymous.com",    "saltstack.com",    "deconsquad.com",    "migom.com",    "tjprc.org",    "worklife.dk",    "food-hub.org"}    start := time.Now()    results := asyncHttpGets(urls)    f, err := os.Create("test.txt")    if err != nil {        fmt.Println(err)        return    }    for _, result := range results {        fmt.Printf("%s status: %s\n", result.url,            result.response.Status)            l, err := f.WriteString(result.url+"\n")            if err != nil {                fmt.Println(err)                f.Close()                return            }            _ = l    }    t := time.Now()    elapsed := t.Sub(start)    fmt.Printf("Ellipsed: %s\n", elapsed)    err = f.Close()    if err != nil {        fmt.Println(err)        return    }    fmt.Println("Buy, world2.")}func asyncHttpGets(urls []string) []*HttpResponse {    ch := make(chan *HttpResponse, len(urls)) // buffered    responses := []*HttpResponse{}    for _, url := range 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            }https://play.golang.org/p/pcKYYM_PgIX
查看完整描述

3 回答

?
慕尼黑5688855

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),并對發出的并發請求數進行限制。


查看完整回答
反對 回復 2022-05-18
?
UYOU

TA貢獻1878條經驗 獲得超4個贊

問題是您在沒有寫入通道的情況下返回錯誤??茨愕膇f 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)


查看完整回答
反對 回復 2022-05-18
?
MYYA

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

}

您可以在存儲庫的示例文件夾中找到示例用法。


查看完整回答
反對 回復 2022-05-18
  • 3 回答
  • 0 關注
  • 122 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號