douzi8916 2016-12-17 16:09
浏览 12
已采纳

同步频道和等待组的最佳实践是什么?

What's the best practice to synchronise wait groups and channels? I want to handle messages and block on a loop, and it appears that delegating the closing of the channel to another go routine seems to be a weird solution?

func Crawl(url string, depth int, fetcher Fetcher) {
    ch := make(chan string)

    var waitGroup sync.WaitGroup
    waitGroup.Add(1)
    go crawlTask(&waitGroup, ch, url, depth, fetcher)

    go func() {
        waitGroup.Wait()
        close(ch)
    }()

    for message := range ch {
        // I want to handle the messages here
        fmt.Println(message)
    }
}

func crawlTask(waitGroup *sync.WaitGroup, ch chan string, url string, depth int, fetcher Fetcher) {
    defer waitGroup.Done()

    if depth <= 0 {
        return
    }
    body, urls, err := fetcher.Fetch(url)

    if err != nil {
        ch <- err.Error()
        return
    }
    ch <- fmt.Sprintf("found: %s %q
", url, body)
    for _, u := range urls {
        waitGroup.Add(1)
        go crawlTask(waitGroup, ch, u, depth-1, fetcher)
    }
}
func main() {
    Crawl("http://golang.org/", 4, fetcher)
}

// truncated from https://tour.golang.org/concurrency/10 webCrawler
  • 写回答

2条回答 默认 最新

  • doudeng9425 2016-12-17 17:11
    关注

    As an alternative to using a waitgroup and extra goroutine, you can you a separate channel for ending goroutines.

    This is (also) idiomatic in Go. It involves blocking using a select control group.

    So you'd have to make a new channel, typically with an empty struct as it's value (eg closeChan := make(chan struct{}) which, when closed (close(closeChan)) would end the goroutine itself.

    Instead of ranging over a chan, you can use a select to block until either fed data or closed.

    The code in Crawl could look something like this:

    for { // instead of ranging over a to-be closed chan
        select {
        case message := <-ch:
            // handle message
        case <-closeChan:
            break // exit goroutine, can use return instead
        }
    }
    

    And then in crawlTask, you could close the closeChan (passed in as another parameter, like ch when you return (I figure that's when you want the other goroutine to end, and stop handling messages?)

    if depth <= 0 {
        close(closeChan)
        return
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么