Concurrency Go webcrawler在检查了大约2000个URL后挂起

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

我有一个程序来检查网页上是否有关键字。但在检查了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    
    })()    
}
type requestReturn结构{
url字符串
状态布尔
}
var超时=时间.持续时间(800*时间.毫秒)
func checkURL(URL[]字符串,kws字符串,threadLimit int)[]字符串{
limitChan:=make(chan int,threadLimit)
确定:=make(chan requestReturn,1)
var结果[]字符串
i:=0
对于;ithreadLimit在这段代码中,您似乎使用了两种形式的并发控制,但都有问题

您已经获得了
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网络连接不足的经验。