gpt4 book ai didi

concurrency - Go webcrawler 在检查大约 2000 个 url 后挂起

转载 作者:IT王子 更新时间:2023-10-29 01:40:01 25 4
gpt4 key购买 nike

我有一个程序可以检查网页上是否有关键字。但是在检查了 1000-3000 个 url 之后,它挂起了。没有输出,不退出,tcp连接数为零。我不知道为什么没有新的连接。

你能给我一些调试建议吗?

type requestReturn struct {    
url string
status bool
}

var timeout = time.Duration(800 * time.Millisecond)

func checkUrls(urls []string, kws string, threadLimit int) []string {
limitChan := make(chan int, threadLimit)
ok := make(chan requestReturn, 1)
var result []string
i := 0
for ; i < threadLimit; i++ {
go func(u string) {
request(u, limitChan, ok, kws)
}(urls[i])
}
for o := range ok {
if o.status {
result = append(result, o.url)
log.Printf("success %s,remain %d", o.url, len(urls)-i)
} else {
log.Printf("fail %s,remain %d", o.url, len(urls)-i)
}
if i < len(urls) {
go func(u string) {
request(u, limitChan, ok, kws)
}(urls[i])
i++
}
}
close(limitChan)
return result
}

func dialTimeout(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, timeout)
}

func request(url string, threadLimit chan int, ok chan requestReturn, kws string) {
threadLimit <- 1
log.Printf("%s, start...", url)
//startTime := time.Now().UnixNano()
rr := requestReturn{url: url}

transport := http.Transport{
Dial: dialTimeout,
DisableKeepAlives: true,
}

client := http.Client{
Transport: &transport,
Timeout: time.Duration(15 * time.Second),
}

resp, e := client.Get(url)
if e != nil {
log.Printf("%q", e)
rr.status = false
return
}

if resp.StatusCode == 200 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("%q", err)
rr.status = false
return
}

content := bytes.NewBuffer(body).String()

matched, err1 := regexp.MatchString(kws, content)
if err1 != nil {
log.Printf("%q", err1)
rr.status = false
} else if matched {
rr.status = true
log.Println(rr.url)
} else {
rr.status = false
}
} else {
rr.status = false
}

defer (func() {
resp.Body.Close()
ok <- rr
//processed := float32(time.Now().UnixNano()-startTime) / 1e9
//log.Printf("%s, status:%t,time:%.3fs", rr.url, rr.status, processed)
<-threadLimit
})()
}

最佳答案

您似乎在这段代码中使用了两种形式的并发控制,但都存在问题。

你有 limitChan ,看起来它被用作信号量(request 在其开始时发送一个值,并在该函数的 defer 中接收一个值)。但是checkUrls还试图确保它只有 threadLimit goroutines 同时运行(通过首先产生那个数字,并且只有在一个人在 ok channel 上报告其结果时才产生更多)。只有其中一个是限制并发所必需的。

由于 defer 的方式,这两种方法都失败了设置于request .有许多 return defer 之前发生的语句, 因此函数可以在不将结果发送到 ok 的情况下完成 channel ,并且没有释放其在 limitChan 中的插槽.在出现足够数量的错误后,checkUrls将停止产生新的 goroutines,你会看到你的挂起。

修复方法是放置 defer在任何 return 之前的声明语句,因此您知道它将始终运行。像这样:

func request(url string, threadLimit chan int, ok chan requestReturn, kws string) {
threadLimit <- 1
rr := requestReturn{url: url}
var resp *http.Response
defer func() {
if resp != nil {
resp.Body.Close()
}
ok <- rr
<-threadLimit
}()
...
}

关于concurrency - Go webcrawler 在检查大约 2000 个 url 后挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23189927/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com