【发布时间】:2018-03-15 13:44:08
【问题描述】:
我有一个正在抓取的网址列表。我想要做的是将所有成功抓取的页面数据存储到一个通道中,当我完成后,将其转储到一个切片中。我不知道我会获得多少成功,所以我不能指定一个固定的长度。我希望代码到达wg.Wait(),然后等到所有wg.Done() 方法被调用,但我从未到达close(queue) 语句。寻找类似的答案,我遇到了这个 SO 答案
https://stackoverflow.com/a/31573574/5721702
作者做了类似的事情:
ports := make(chan string)
toScan := make(chan int)
var wg sync.WaitGroup
// make 100 workers for dialing
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for p := range toScan {
ports <- worker(*host, p)
}
}()
}
// close our receiving ports channel once all workers are done
go func() {
wg.Wait()
close(ports)
}()
只要我将wg.Wait() 包裹在 goroutine 中,就会到达 close(queue):
urls := getListOfURLS()
activities := make([]Activity, 0, limit)
queue := make(chan Activity)
for i, activityURL := range urls {
wg.Add(1)
go func(i int, url string) {
defer wg.Done()
activity, err := extractDetail(url)
if err != nil {
log.Println(err)
return
}
queue <- activity
}(i, activityURL)
}
// calling it like this without the goroutine causes the execution to hang
// wg.Wait()
// close(queue)
// calling it like this successfully waits
go func() {
wg.Wait()
close(queue)
}()
for a := range queue {
// block channel until valid url is added to queue
// once all are added, close it
activities = append(activities, a)
}
如果我不为wg.Wait() 使用goroutine,为什么代码无法到达close?我认为所有defer wg.Done() 语句都被调用,所以最终它会清除,因为它到达wg.Wait()。是否与在我的频道中接收值有关?
【问题讨论】:
-
你能展示整个代码吗?
-
默认情况下,通道是无缓冲的,这意味着如果有相应的接收准备好接收发送的值,它们将只接受发送。因此,当您将活动发送到队列时,没有相应的接收它被阻塞了。所有的 goroutine 都被阻塞了,最后 wg.wait 会挂起。有一种叫做缓冲通道的概念,可以用来缓冲多个输入。通过gobyexample.com/channel-buffering
标签: asynchronous go goroutine