【发布时间】:2025-12-05 02:20:15
【问题描述】:
我有一个函数可以递归地生成 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
}
}
我想知道如何退出所有这些 goroutine——即关闭ch--一旦我找到某种类型的节点或满足其他一些条件。我尝试使用quit 通道,在生成新的 goroutine 之前会对其进行轮询,如果收到一个值,则关闭 ch,但这会导致一些 goroutine 尝试在刚刚被另一个关闭的通道上发送的竞争条件一。我正在考虑使用互斥锁,但使用互斥锁保护通道似乎不优雅并且违背了 go 的精神。有没有一种惯用的方式来使用频道来做到这一点?如果没有,有什么办法吗?任何意见表示赞赏!
【问题讨论】:
标签: go