1 回答

TA貢獻1770條經驗 獲得超3個贊
您可以使用 sync.WaitGroup(請參閱文檔)來控制工作人員的生命周期,并使用非阻塞發送,以便工作人員在嘗試排隊更多作業時不會死鎖:
package main
import "sync"
const workers = 4
type job struct{}
func (j *job) do(enqueue func(job)) {
// do the job, calling enqueue() for subtasks as needed
}
func main() {
jobs, wg := make(chan job), new(sync.WaitGroup)
var enqueue func(job)
// workers
for i := 0; i < workers; i++ {
go func() {
for j := range jobs {
j.do(enqueue)
wg.Done()
}
}()
}
// how to queue a job
enqueue = func(j job) {
wg.Add(1)
select {
case jobs <- j: // another worker took it
default: // no free worker; do the job now
j.do(enqueue)
wg.Done()
}
}
todo := make([]job, 1000)
for _, j := range todo {
enqueue(j)
}
wg.Wait()
close(jobs)
}
嘗試使用緩沖通道避免死鎖的困難在于,您必須預先分配一個足夠大的通道,以確保在不阻塞的情況下保持所有掛起的任務。除非您有少量已知的 URL 可供抓取,否則會出現問題。
當您回退到在當前線程中進行普通遞歸時,您沒有那個靜態緩沖區大小限制。當然,仍然存在限制:如果有太多工作待處理,您可能會耗盡 RAM,理論上您可以通過深度遞歸耗盡堆棧(但這很難?。?。因此,如果您要對整個 Web 進行爬行,則需要以更復雜的方式跟蹤待處理的任務。
最后,作為一個更完整的例子,我對這段代碼并不感到非常自豪,但我碰巧寫了一個函數來啟動一個并行排序,它以與獲取 URL 的方式相同的方式遞歸。
- 1 回答
- 0 關注
- 197 瀏覽
添加回答
舉報