我有一个函数可以递归地生成 goroutine 来遍历 DOM 树,将它们找到的节点放入它们之间共享的通道中。
import (
"golang.org/x/net/html"
"sync"
)
func walk(doc *html.Node, ch chan *html.Node) {
var wg sync.WaitGroup
defer close(ch)
var f func(*html.Node)
f = func(n *html.Node) {
defer wg.Done()
ch <- n
for c := n.FirstChild; c != nil; c = c.NextSibling {
wg.Add(1)
go f(c)
}
}
wg.Add(1)
go f(doc)
wg.Wait()
}
我会这样称呼
// get the webpage using http
// parse the html into doc
ch := make(chan *html.Node)
go walk(doc, ch)
for c := range ch {
if someCondition(c) {
// do something with c
// quit all goroutines spawned by walk
}
}
我想知道如何退出所有这些 goroutines——即关闭ch——一旦我找到了某种类型的节点或其他一些条件已经满足。我曾尝试使用一个quit通道,该通道会在生成新的 goroutine 之前进行轮询并ch在收到值时关闭,但这会导致竞争条件,其中一些 goroutine 尝试在刚刚被另一个 goroutine 关闭的通道上发送。我正在考虑使用互斥锁,但它似乎不够优雅并且违背了使用互斥锁保护通道的精神。有没有一种惯用的方法可以使用频道来做到这一点?如果没有,有什么办法吗?任何输入表示赞赏!
桃花长相依
相关分类