为什么我的代码导致失速或竞争状况?

Eva*_*eri 0 concurrency go goroutine

出于某种原因,一旦我开始通过我的goroutine中的通道添加字符串,代码在我运行时就会停止.我认为这是一个范围/闭包问题,所以我将所有代码直接移动到函数中无济于事.我查看了Golang的文档,所有示例都与我的相似,所以我对于出了什么问题毫无头绪.

func getPage(url string, c chan<- string, swg sizedwaitgroup.SizedWaitGroup) {
    defer swg.Done()
    doc, err := goquery.NewDocument(url)

    if err != nil{
        fmt.Println(err)
    }

    nodes := doc.Find(".v-card .info")
    for i := range nodes.Nodes {
        el := nodes.Eq(i)
        var name string
        if el.Find("h3.n span").Size() != 0{
            name = el.Find("h3.n span").Text()
        }else if el.Find("h3.n").Size() != 0{
            name = el.Find("h3.n").Text()
        }

        address := el.Find(".adr").Text()
        phoneNumber := el.Find(".phone.primary").Text()
        website, _ := el.Find(".track-visit-website").Attr("href")
        //c <- map[string] string{"name":name,"address":address,"Phone Number": phoneNumber,"website": website,};
        c <- fmt.Sprint("%s%s%s%s",name,address,phoneNumber,website)
        fmt.Println([]string{name,address,phoneNumber,website,})

    }
}

func getNumPages(url string) int{
    doc, err := goquery.NewDocument(url)
    if err != nil{
        fmt.Println(err);
    }
    pagination := strings.Split(doc.Find(".pagination p").Contents().Eq(1).Text()," ")
    numItems, _ := strconv.Atoi(pagination[len(pagination)-1])
    return int(math.Ceil(float64(numItems)/30))
}


func main() {
    arrChan := make(chan string)
    swg := sizedwaitgroup.New(8)
    zips := []string{"78705","78710","78715"}

    for _, item := range zips{
        swg.Add()
        go getPage(fmt.Sprintf(base_url,item,1),arrChan,swg)
    }
    swg.Wait()

}
Run Code Online (Sandbox Code Playgroud)

编辑:所以我通过传递sizewaitgroup作为参考来修复它,但当我删除缓冲区它不起作用是否意味着我需要知道将提前向通道发送多少元素?

pho*_*zed 5

问题

根据您发布的代码建立科林斯图尔特的答案,据我所知,您的问题实际上是阅读您的问题arrChan.你写了它,但你的代码中没有你从中读取它的地方.

文档:

如果通道未缓冲,则发送方将阻塞,直到接收方收到该值.如果通道有缓冲区,则发送方仅阻塞,直到将值复制到缓冲区为止; 如果缓冲区已满,则表示等待某个接收方检索到某个值.

通过使通道缓冲,正在发生的事情是您的代码不再阻塞通道写操作,看起来像这样的行:

c <- fmt.Sprint("%s%s%s%s",name,address,phoneNumber,website)
Run Code Online (Sandbox Code Playgroud)

我的猜测是,如果你仍然在频道大小为5000时挂着,那是因为你在所有循环中返回的值超过了5000 node.Nodes.一旦缓冲的通道已满,操作将阻塞,直到通道有空间,就像您正在写入无缓冲通道一样.

固定

这是一个最小的例子,向您展示如何修复这样的事情(基本上只是添加一个阅读器)

package main

import "sync"

func getPage(item string, c chan<- string) {
    c <- item
}

func readChannel(c <-chan string) {
    for {
        <-c
    }
}

func main() {
    arrChan := make(chan string)
    wg := sync.WaitGroup{}
    zips := []string{"78705", "78710", "78715"}

    for _, item := range zips {
        wg.Add(1)
        go func() {
            defer wg.Done()
            getPage(item, arrChan)
        }()
    }
    go readChannel(arrChan) // comment this out and you'll deadlock
    wg.Wait()
}
Run Code Online (Sandbox Code Playgroud)