我想了解我围绕WaitGroups的逻辑是否正确,并查看是否有一种更有效的方法来构造我的代码。目的是尽可能快地执行任务。
我的代码填充通过标准输入填充的_urls
通道。然后,我将创建两个WaitGroup,一个从该_urls
通道读取,另一个从_downloads
通道读取,该通道从第一个WaitGroup中的goroutine提供。
基本上,代码看起来像这样:
// declare channels
_urls := make(chan string)
_downloads := make(chan string)
// first waitgroup with 2 goroutines
var wg sync.WaitGroup
for i := 0; i < concurrency; i++ {
wg.Add(2)
go func() {
defer wg.Done()
for url := range _urls {
// perform GET request and inspect the responseBody
}
}()
go func() {
defer wg.Done()
for url := range _urls {
// perform a HEAD request to look for a certain file
// if the file exists, send to the _downloads channel
_downloads <- url
}
}()
}
// second waitgroup with 1 goroutine
var dwg sync.WaitGroup
for i := 0; i < concurrency; i++ {
dwg.Add(1)
go func() {
defer wg.Done()
for url := range _downloads {
// perform the download
}
}()
}
[我担心这是馈送_downloads
通道的有效方法,还是仅在第一个WaitGroup中执行下载才有意义?
我使用工人池模式https://gobyexample.com/worker-pools进行了类似的操作。如果您希望最大化并发性,那么可能是正确的方向。
它使用go接口抽象作业,因此它可以是HEAD,GET,Download或将来发生的其他任何有意义的事情。调度程序将作业发送到管理工作池的调度程序,并将结果发回。
这里是README和代码的链接。
它使用等待组来跟踪活动工人的数量,而不是工作。工人执行for {} loop
,仅当他们从已完成的通道中读取为true时,才退出。在这种情况下,使用等待组是为了正常关机。在您的示例中,许多工作人员可能正在长时间下载。因此,您的关闭逻辑可以在关闭之前等待剩余N个作业。
对于您的用例,这可能是过大的。