我有一个简单的代码,可为文本文件(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) }
您正在一次启动所有请求。如果文件中有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() }