Je suis en train de construire un robot qui prend une URL, en extrait des liens et en visite chacun à une certaine profondeur; faire un arbre de chemins sur un site spécifique.Quelle est la meilleure façon de gérer "trop de fichiers ouverts"?
La façon dont je mis en œuvre le parallélisme pour ce crawler est que je visite chaque nouvelle URL trouvée dès qu'il a trouvé comme ceci:
func main() {
link := "https://example.com"
wg := new(sync.WaitGroup)
wg.Add(1)
q := make(chan string)
go deduplicate(q, wg)
q <- link
wg.Wait()
}
func deduplicate(ch chan string, wg *sync.WaitGroup) {
for link := range ch {
// seen is a global variable that holds all seen URLs
if seen[link] {
wg.Done()
continue
}
seen[link] = true
go crawl(link, ch, wg)
}
}
func crawl(link string, q chan string, wg *sync.WaitGroup) {
// handle the link and create a variable "links" containing the links found inside the page
wg.Add(len(links))
for _, l := range links {
q <- l}
}
}
Cela fonctionne bien pour les sites relativement petits, mais quand je le lance sur une grand avec beaucoup de lien partout, je commence à obtenir une de ces deux erreurs sur certaines demandes: socket: too many open files
et no such host
(l'hôte est en effet là).
Quelle est la meilleure façon de gérer cela? Dois-je vérifier ces erreurs et suspendre l'exécution quand je les reçois pendant un certain temps jusqu'à ce que les autres demandes soient terminées? Ou spécifier un nombre maximum de demandes possibles à un certain moment? (ce qui est plus logique pour moi mais ne sait pas comment coder exactement)
Vous êtes confronté à un problème lié à la limite des fichiers ouverts par utilisateur qui est contrôlée par le système d'exploitation. Si vous utilisez Linux/Unix, vous pouvez probablement augmenter la limite en utilisant la commande ulimit -n 4096. Cette commande a un seuil et elle ne peut pas définir le nombre de fichiers ouverts que vous voulez . Donc, si vous voulez pousser plus loin, vous devez modifier le fichier /etc/security/limits.conf et définir dur et une limite douce. –
En outre, vous commencez un goroutine pour chaque lien que vous enconnerez et s'il y en a plusieurs à un certain point, cela va à l'encontre du but de goroutines et prend plus de temps à faire la tâche. Vous devriez essayer d'avoir un nombre fixe de goroutines pour faire le traitement et lire depuis un canal au lieu d'en commencer un nouveau pour chaque lien. Jetez un oeil à https://blog.golang.org/pipelines – Topo
Ou peut-être un modèle comme: https://gobyexample.com/worker-pools? (BTW, votre utilisation 'WaitGroup' est assez étrange, ajoutez 1 pour chaque goroutine, et différer' Done' de chaque goroutine.Tout autre demande des bogues) – JimB