Wget parallèle dans Bash

Je reçois un tas de pages relativement petites sur un site Web et je me demandais si je pouvais le faire en parallèle dans Bash. Actuellement, mon code ressemble à ceci, mais il faut du temps pour s’exécuter (je pense que ce qui me ralentit est la latence dans la connexion).

for i in {1..42} do wget "https://www.example.com/page$i.html" done 

J’ai entendu parler de l’utilisation de xargs, mais je n’y connais rien et la page de manuel est très confuse. Des idées? Est-il même possible de le faire en parallèle? Y a-t-il un autre moyen pour attaquer cela?

    Plutôt préférable de pousser wget en arrière-plan en utilisant & ou -b , vous pouvez utiliser xargs avec le même effet et mieux.

    L’avantage est que xargs se synchronisera correctement sans travail supplémentaire. Cela signifie que vous êtes en sécurité pour accéder aux fichiers téléchargés (en supposant qu’aucune erreur ne se produise). Une fois xargs terminé, tous les téléchargements seront terminés (ou échoués) et le code de sortie vous indiquera si tout s’est bien passé. Ceci est beaucoup plus préférable que d’attendre avec le sleep et de faire des tests manuellement.

    En supposant que URL_LIST est une variable contenant toutes les URL (peut être construite avec une boucle dans l’exemple de l’OP, mais pourrait également être une liste générée manuellement), exécutez ceci:

     echo $URL_LIST | xargs -n 1 -P 8 wget -q 

    passera un argument à la fois ( -n 1 ) à wget et exécutera au plus 8 processus wget parallèles à la fois ( -P 8 ). xarg revient après la fin du dernier processus généré, ce que nous voulions savoir. Aucune ruse supplémentaire nécessaire.

    Le “nombre magique” de 8 téléchargements parallèles que j’ai choisis n’est pas figé, mais c’est probablement un bon compromis. Il y a deux facteurs dans la “maximisation” d’une série de téléchargements:

    On remplit “le câble”, c’est-à-dire en utilisant la bande passante disponible. En supposant des conditions “normales” (le serveur a plus de bande passante que le client), c’est déjà le cas avec un ou deux téléchargements au maximum. Lancer plus de connexions au problème entraînera uniquement la suppression des paquets et le contrôle de l’encombrement TCP, et le téléchargement de N avec une bande passante asymptotiquement égale à 1 / N , avec le même effet net (moins les paquets supprimés, moins la récupération de la taille de la fenêtre). Il est normal que des paquets soient supprimés dans un réseau IP. C’est ainsi que le contrôle de la congestion est censé fonctionner (même avec une seule connexion), et l’impact est normalement pratiquement nul. Cependant, avoir un nombre de connexions déraisonnablement élevé amplifie cet effet, de sorte qu’il peut être perceptible. En tout cas, ça ne fait rien plus vite.

    Le second facteur est l’établissement de la connexion et le traitement de la demande. Ici, avoir quelques connexions supplémentaires en vol est vraiment utile . Le problème auquel nous sums confrontés est la latence de deux allers-retours (généralement 20 à 40 ms dans la même zone géographique, 200 à 300 ms intercontinentaux) plus les impairs de 1 à 2 millisecondes nécessaires au serveur pour traiter la demande et envoyer une réponse. à la prise. Ce n’est pas beaucoup de temps en soi , mais multiplié par quelques centaines de milliers de demandes, cela ajoute rapidement.
    Avoir entre une demi-douzaine et une douzaine de demandes en vol cache la plupart ou la totalité de cette latence (elle est toujours là, mais comme elle se chevauche, elle ne résume pas!). Dans le même temps, le fait de ne disposer que de quelques connexions simultanées n’a pas d’effets néfastes, tels qu’un encombrement excessif ou le fait de forcer un serveur à créer de nouveaux processus.

    Exécuter les tâches en arrière-plan n’est pas une solution évolutive: si vous récupérez 10000 URL, vous ne souhaitez probablement en récupérer que quelques-unes (disons 100) en parallèle. GNU Parallel est fait pour cela:

     seq 10000 | parallel -j100 wget https://www.example.com/page{}.html 

    Voir la page de manuel pour plus d’exemples: http://www.gnu.org/software/parallel/man.html#example__download_10_images_for_each_of_the_past_30_days

    Vous pouvez utiliser l’option -b :

     wget -b "https://www.example.com/page$i.html" 

    Si vous ne voulez pas de fichiers journaux, ajoutez l’option -o /dev/null .

     -o FILE journal des messages au fichier.
    

    L’ajout d’une esperluette à une commande permet de l’exécuter en arrière-plan

     for i in {1..42} do wget "https://www.example.com/page$i.html" & done 

    La version 2 de wget semble implémenter plusieurs connexions. Le lien du projet dans github: https://github.com/rockdaboot/wget2