Webcrawler em Go
Estou tentando criar um rastreador da Web no Go, onde gostaria de especificar o número máximo de trabalhadores simultâneos. Todos eles estarão trabalhando enquanto houver um link para explorar na fila. Quando a fila tiver menos elementos que trabalhadores, os trabalhadores deverão gritar, mas continuar caso mais links sejam encontrados.
O código que eu tentei é
const max_workers = 6
// simulating links with int
func crawl(wg *sync.WaitGroup, queue chan int) {
for element := range queue {
wg.Done() // why is defer here causing a deadlock?
fmt.Println("adding 2 new elements ")
if element%2 == 0 {
wg.Add(2)
queue <- (element*100 + 11)
queue <- (element*100 + 33)
}
}
}
func main() {
var wg sync.WaitGroup
queue := make(chan int, 10)
queue <- 0
queue <- 1
queue <- 2
queue <- 3
var min int
if (len(queue) < max_workers) {
min = len(queue)
} else {
min = max_workers
}
for i := 0; i < min; i++ {
wg.Add(1)
go crawl(&wg, queue)
}
wg.Wait()
close(queue)
}
Isso parece funcionar, mas há um problema: tenho que preencher a fila com mais de um elemento ao iniciar. Gostaria que iniciasse a partir de uma (única) página inicial (no meu exemploqueue <- 0
) e aumente / reduza o pool de trabalho dinamicamente.
Minhas perguntas são:
como posso obter comportamento?
por que adiarwg.Done()
causando impasse? É normalwg.Done()
a função quando está realmente concluída? Eu acho que sem odefer
a goroutine não está esperando a outra parte terminar (o que pode levar mais tempo no exemplo real de análise de HTML).