一尘不染

使用goroutine时HTTP GET请求的时间响应

go

我有一个简单的代码,可为文本文件(url_list.txt)中列出的每个URL打印GET响应时间。

当顺序触发请求时,返回的时间对应于各个URL的预期响应时间。

但是,当同时执行相同的代码时,返回的响应时间通常比预期的要高。

看来我在http.Get(url)调用之前捕获的 time_start
并不是实际发送请求的时间。我猜http.Get(url)的执行排队了一段时间。

使用goroutine时,是否有更好的方法来捕获URL响应时间?

这是我的代码:

顺序请求:

package main

import ("fmt"
        "net/http"
        "io/ioutil"
        "time"
        "strings"
)

func get_resp_time(url string) {
        time_start := time.Now()
        resp, err := http.Get(url)
        if err != nil {
            panic(err)
        }
        defer resp.Body.Close()
        fmt.Println(time.Since(time_start), url)
}

func main() {
    content, _ := ioutil.ReadFile("url_list.txt")
    urls := strings.Split(string(content), "\n")

    for _, url := range urls {
        get_resp_time(url)
        //go get_resp_time(url)
    }

    //time.Sleep(20 * time.Second)
}

并发请求:

package main

import ("fmt"
        "net/http"
        "io/ioutil"
        "time"
        "strings"
)

func get_resp_time(url string) {
        time_start := time.Now()
        resp, err := http.Get(url)
        if err != nil {
            panic(err)
        }
        defer resp.Body.Close()
        fmt.Println(time.Since(time_start), url)
}

func main() {
    content, _ := ioutil.ReadFile("url_list.txt")
    urls := strings.Split(string(content), "\n")

    for _, url := range urls {
        //get_resp_time(url)
        go get_resp_time(url)
    }

    time.Sleep(20 * time.Second)
}

阅读 268

收藏
2020-07-02

共1个答案

一尘不染

您正在一次启动所有请求。如果文件中有1000个url,则您一次要启动1000个go例程。这可能有效,但可能会给您有关套接字或文件句柄不足的错误。我建议一次启动一定数量的抓取操作,例如下面的代码。

这也将有助于时间安排。

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "strings"
    "sync"
    "time"
)

func get_resp_time(url string) {
    time_start := time.Now()
    resp, err := http.Get(url)
    if err != nil {
        log.Printf("Error fetching: %v", err)
    }
    defer resp.Body.Close()
    fmt.Println(time.Since(time_start), url)
}

func main() {
    content, _ := ioutil.ReadFile("url_list.txt")
    urls := strings.Split(string(content), "\n")

    const workers = 25

    wg := new(sync.WaitGroup)
    in := make(chan string, 2*workers)

    for i := 0; i < workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for url := range in {
                get_resp_time(url)
            }
        }()
    }

    for _, url := range urls {
        if url != "" {
            in <- url
        }
    }
    close(in)
    wg.Wait()
}
2020-07-02