Concurrency Go webcrawler在检查了大约2000个URL后挂起
我有一个程序来检查网页上是否有关键字。但在检查了1000-3000个URL后,它会挂起。没有输出,也不退出,tcp连接数为零。我不知道为什么没有新的联系 你能给我一些如何调试它的建议吗Concurrency Go webcrawler在检查了大约2000个URL后挂起,concurrency,go,freeze,Concurrency,Go,Freeze,我有一个程序来检查网页上是否有关键字。但在检查了1000-3000个URL后,它会挂起。没有输出,也不退出,tcp连接数为零。我不知道为什么没有新的联系 你能给我一些如何调试它的建议吗 type requestReturn struct { url string status bool } var timeout = time.Duration(800 * time.Millisecond) func checkUrls(urls []strin
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
})()
}
type requestReturn结构{
url字符串
状态布尔
}
var超时=时间.持续时间(800*时间.毫秒)
func checkURL(URL[]字符串,kws字符串,threadLimit int)[]字符串{
limitChan:=make(chan int,threadLimit)
确定:=make(chan requestReturn,1)
var结果[]字符串
i:=0
对于;i threadLimit在这段代码中,您似乎使用了两种形式的并发控制,但都有问题
您已经获得了limitChan
,它看起来像是被用作信号量(request
在其开始时发送一个值,并在该函数中的defer
中接收一个值)。但是checkurl
也试图确保它只同时运行threadLimit
goroutines(首先生成该数字,并且仅当一个人在ok
频道上报告其结果时才生成更多)。应该只需要其中一个来限制并发性
由于在请求中设置延迟
的方式,这两种方法都失败了。在延迟
之前出现了许多返回
语句,因此函数可以在不将结果发送到确定
频道的情况下完成,也不需要释放limitChan
。在出现足够数量的错误后,检查URL
将停止生成新的goroutine,您将看到挂起
解决方法是将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
}()
...
}
func请求(url字符串、threadLimit chan int、ok chan requestReturn、kws字符串){
threadLimit Play发布了一个格式化的可编译代码。完整的代码是:这是在Windows上发生的吗?如果在不到五分钟的时间内创建了超过3000个套接字,我有Windows网络连接不足的经验。