如何解决如何在并发goroutine中超时截止后继续“继续”?
我正在对不同URL进行并发GET请求(在这种情况下为1000)。对于这些要求,我遵循了消费者-生产者的设计。有50个工人(goroutines-爬虫)和1个生产者(使用url填充频道)。
问题:我已将客户端中的超时设置为15秒(我不想为每个请求等待15秒以上)。但是,当URL使goroutine等待15秒以上时,我的代码会以
退出超出上下文期限(读取正文时Client.Timeout或上下文取消)
期望的行为:当服务器耗时超过15秒时,我希望相关的goroutine仅在下一个URL上继续
这是代码段:
package main
import (
"bufio"
"fmt"
"io"
"log"
"net/http"
"os"
"sync"
"time"
)
func crawler(wg *sync.WaitGroup,urlChannel <-chan string) {
defer wg.Done()
client := &http.Client{Timeout: 15 * time.Second} // single client is sufficient for multiple requests
for urlItem := range urlChannel {
req1,_ := http.NewRequest("GET","http://"+urlItem,nil) // generating the request
req1.Header.Add("User-agent","Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/74.0") // changing user-agent
resp1,respErr1 := client.Do(req1) // sending the prepared request and getting the response
if respErr1 != nil {
fmt.Println("server error",urlItem)
continue
}
if resp1.StatusCode/100 == 2 { // means server responded with 2xx code
f1,fileErr1 := os.Create("200/" + urlItem + "_original.txt") // creating the relative file
if fileErr1 != nil {
fmt.Println("file error",urlItem)
log.Fatal(fileErr1)
}
_,writeErr1 := io.Copy(f1,resp1.Body) // writing the sourcecode into our file
if writeErr1 != nil {
fmt.Println("file error",urlItem)
log.Fatal(writeErr1)
}
f1.Close()
resp1.Body.Close()
fmt.Println("success:",urlItem)
}
}
}
func main() {
var wg sync.WaitGroup // synchronization to wait for all the goroutines
file,err := os.Open("urls.txt") // the file containing the url's
if err != nil {
log.Fatal(err)
}
defer file.Close() // don't forget to close the file
urlChannel := make(chan string) // create a channel to store all the url's
_ = os.Mkdir("200",0755) // if it's there,it will create an error,and we will simply ignore it
for i := 0; i < 50; i++ {
wg.Add(1)
go crawler(&wg,urlChannel)
}
scanner := bufio.NewScanner(file) // each line has another url
for scanner.Scan() {
urlChannel <- scanner.Text()
}
close(urlChannel)
wg.Wait()
}
具体地说,我以为我在这里处理问题(但显然我没有):
resp1,respErr1 := client.Do(req1)
// sending the prepared request and getting the response
if respErr1 != nil {
fmt.Println("server error",urlItem)
continue
}
如何实现所需的行为(如果达到超时则跳过URL)?
解决方法
可能在这里:
_,writeErr1 := io.Copy(f1,resp1.Body) // writing the sourcecode into our file
if writeErr1 != nil {
fmt.Println("file error",urlItem)
log.Fatal(writeErr1)
}
此操作的结果不一定是写入错误,它可能是读取错误,在这种情况下,可能是。读取响应正文会超时。
在这种情况下,请勿致电log.Fatal
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。