代码之家  ›  专栏  ›  技术社区  ›  hexagonNoah

如何解决go中的分段冲突?

  •  -1
  • hexagonNoah  · 技术社区  · 4 年前

    我正在go中编写一个spider,到目前为止,我有以下代码:

    
    import (
        "fmt"
        "math/rand"
        "net/http"
        "runtime"
        "time"
    
        "golang.org/x/net/html"
    )
    
    func handleEnd() {
        //handle end (close channels, etc)
        fmt.Println("Placeholder")
    }
    
    func worker(c chan string) {
        var url string
        url = <-c
        fmt.Println(url)
        //get the url
        resp, err := http.Get(url)
        defer resp.Body.Close()
        if err != nil {
            fmt.Println(err)
            //we should log this incase this is in the background
        }
    
        //operate on it
        //find links
        z := html.NewTokenizer(resp.Body)
        for {
            tt := z.Next()
    
            switch {
            case tt == html.ErrorToken:
                // End of the document, we're done
                return
            case tt == html.StartTagToken:
                t := z.Token()
    
                isAnchor := t.Data == "a"
                if isAnchor {
                    fmt.Println("We found a link!")
                }
            }
        }
        //handle local links()
        //send links to channel
        //}
    }
    
    func genStartUrls(howMany, length int) []string {
        var ans []string
        var letters = []rune("abcdefghijklmnopqrstuvwxyz")
        rand.Seed(time.Now().UnixNano())
        for i := 0; i < howMany; i++ {
            b := make([]byte, length)
            for i := range b {
                b[i] = byte(letters[rand.Intn(len(letters))])
            }
            ans = append(ans, "http://"+string(b)+".com")
        }
        return ans
    }
    
    func main() {
        defer handleEnd()
        workers := 3
        l := make(chan string, 10000)
        defer close(l)
        for _, url := range genStartUrls(100, 3) {
            l <- url
        }
        for i := 0; i < workers; i++ {
            go worker(l)
        }
        for {
            runtime.Gosched()
        }
    }
    

    起初,它按预期工作(它从页面中找到了HREF),但当我打破它并再次运行它,然后再做几次同样的事情时,我得到了以下错误:

    [signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x6454f1]
    
    goroutine 7 [running]:
    main.worker(0xc0000662a0)
            /home/name/go/src/spider/main.go:25 +0x121
    created by main.main
            /home/name/go/src/spider/main.go:85 +0x138
    exit status 2
    

    当我重新启动电脑时,这个问题在程序运行几次后就消失了,但随后又回来了。这让我觉得goroutines可能不会在我的主程序结束时结束,而是继续作为僵尸进程。如何修复此错误?

    1 回复  |  直到 4 年前
        1
  •  2
  •   Burak Serdar    4 年前

    程序结束后,Goroutines无法继续。

    以下几行可能是问题的根源:

        resp, err := http.Get(url)
        defer resp.Body.Close()
        if err != nil {
    

    你必须搬家 defer 在错误检查之后,因为如果有错误, resp 将为零,并且 defer resp.Body.Close() 这将失败。

       resp, err := http.Get(url)
       if err != nil {
          ...
          return err
       }
       defer resp.Body.Close()