Une meilleure trouvaille Unix avec traitement parallèle?

43

L’ find(1)utilitaire unix m’est très utile pour effectuer une action sur de nombreux fichiers correspondant à certaines spécifications, par exemple:

find /dump -type f -name '*.xml' -exec java -jar ProcessFile.jar {} \;

Ce qui précède peut exécuter un script ou un outil sur chaque fichier XML d’un répertoire particulier.

Disons que mon script / programme prend beaucoup de temps de calcul et que j'ai 8 processeurs. Ce serait bien de pouvoir traiter jusqu'à 8 fichiers à la fois.

GNU make permet le traitement de travaux en parallèle avec l’ -jindicateur, mais findne semble pas avoir une telle fonctionnalité. Existe-t-il une autre méthode générique d’ordonnancement des travaux pour aborder cette question?

PP.
la source

Réponses:

65

xargsavec l' -Poption (nombre de processus). Supposons que je veuille compresser tous les fichiers journaux d’un répertoire sur une machine de 4 cpu:

find . -name '*.log' -mtime +3 -print0 | xargs -0 -P 4 bzip2

Vous pouvez également indiquer -n <number>le nombre maximal d'unités de travail par processus. Alors disons que j'avais 2500 fichiers et j'ai dit:

find . -name '*.log' -mtime +3 -print0 | xargs -0 -n 500 -P 4 bzip2

Cela lancerait 4 bzip2processus, chacun contenant 500 fichiers, puis, lorsque le premier serait terminé, un autre processus serait lancé pour les 500 derniers fichiers.

Vous ne savez pas pourquoi la réponse précédente utilise xargs et make , vous avez deux moteurs parallèles!

Gaius
la source
7
Avec find / xargs, faites attention: find utilise par défaut les nouvelles lignes en tant que délimiteurs de sortie, mais xargs utilise par défaut les espaces comme délimiteurs d’entrée. Utilisez -0 sur les deux pour plus de sécurité, ou passez en mode parallèle GNU, qui utilise par défaut les nouvelles lignes comme délimiteurs d’entrée (sortie correspondante à find).
éphémient
1
Waouh incroyable! Je viens de vérifier, et c'est vrai, xargs a une -Poption!
PP.
Attention à ne pas utiliser le xargs -P- il y a un bogue jamais corrigé de garbling la sortie (contrairement à parallel) chaque fois que 2 threads produisent une sortie au même moment précis ...
Vlad
34

GNU parallel peut aussi aider.

find /dump -type f -name '*.xml' | parallel -j8 java -jar ProcessFile.jar {}

Notez que sans l' -j8argument, parallelle nombre de cœurs sur votre machine est défini par défaut :-)

éphémère
la source
6

Pas besoin de "réparer" find- utilisez make-vous pour gérer le parallélisme.

Demandez à votre processus de créer un fichier journal ou un autre fichier de sortie, puis utilisez un fichier Makefile comme celui-ci:

.SUFFIXES:  .xml .out

.xml.out:
        java -jar ProcessFile.jar $< 1> $@

et invoqué ainsi:

find /dump -type f -name '*.xml' | sed -e 's/\.xml$/.out/' | xargs make -j8

Mieux encore, si vous veillez à ce que le fichier de sortie ne soit créé qu’une fois le processus Java terminé, vous pouvez tirer parti de makela gestion des dépendances pour vous assurer que seuls les fichiers non traités seront exécutés la prochaine fois.

Alnitak
la source
1
Espérons qu'il n'y a pas d'espaces ou d'autres caractères "intéressants" dans ces noms de fichiers; Make ne gère pas ceux très élégamment.
éphémient
Excellente idée! Jamais pensé à utiliser des makefiles comme celui-ci.
oscfri
3

Find a une option parallèle que vous pouvez utiliser directement à l'aide du symbole "+"; aucun xargs requis. En le combinant avec grep, il peut déchirer rapidement votre arbre à la recherche de correspondances. par exemple, si je recherche tous les fichiers de mon répertoire sources contenant la chaîne 'foo', je peux invoquer
find sources -type f -exec grep -H foo {} +

Mark Evans
la source
12
En lisant le manuel de recherche, vous pouvez voir que la -exec command +syntaxe ne l’exécute pas en parallèle, mais "regroupe" plusieurs fichiers et lance la commande avec plusieurs fichiers comme arguments à la fois. Il arrive que grep puisse parcourir ses cibles en parallèle.
Gyscos