Besoin de suggestions d'experts sur la comparaison ci-dessous:
Segment de code utilisant une boucle:
for file in `cat large_file_list`
do
gzip -d $file
done
Segment de code utilisant une expansion simple:
gzip -d `cat large_file_list`
Lequel sera le plus rapide? Vous devez manipuler un grand ensemble de données.
linux
bash
shell-script
shell
Léon
la source
la source
gzip
sur votre système, du nombre de fichiers dans la liste des fichiers et de la taille de ces fichiers.xargs gzip -d < large_file_list
mais faites attention aux espaces dans les noms de fichiers, peut-être avectr \\n \\0 large_file_list | xargs -0 gzip -d
Réponses:
Complications
Les éléments suivants ne fonctionnent que parfois:
Trois problèmes se posent (dans la
bash
plupart des autres obus de type Bourne):Il échouera si un nom de fichier contient un espace ou des caractères de nouvelle ligne (en supposant qu'il
$IFS
n'a pas été modifié). Cela est dû au fractionnement du mot du shell .Il est également susceptible d'échouer si un nom de fichier contient des caractères globaux. Cela est dû au fait que le shell appliquera l' extension de nom de chemin à la liste de fichiers.
Il échouera également si les noms de fichiers commencent par
-
(siPOSIXLY_CORRECT=1
cela ne s'applique qu'au premier fichier) ou si un nom de fichier l'est-
.Il échouera également s'il contient trop de noms de fichiers pour tenir sur une seule ligne de commande.
Le code ci-dessous est soumis aux mêmes problèmes que le code ci-dessus (sauf pour le quatrième)
Solution fiable
Si votre
large_file_list
a exactement un nom de fichier par ligne, et qu'un fichier appelé-
n'en fait pas partie, et que vous êtes sur un système GNU, utilisez:-d'\n'
indiquexargs
de traiter chaque ligne d'entrée comme un nom de fichier distinct.-r
indique dexargs
ne pas exécuter la commande si le fichier d'entrée est vide.--
indiquegzip
que les arguments suivants ne doivent pas être traités comme des options même s'ils commencent par-
.-
seul serait toujours traité comme-
au lieu du fichier appelé-
.xargs
mettra de nombreux noms de fichiers sur chaque ligne de commande, mais pas tellement qu'il dépasse la limite de ligne de commande. Cela réduit le nombre de fois qu'ungzip
processus doit être démarré et rend donc cela rapide. Il est également sûr: les noms de fichiers seront également protégés contre le fractionnement de mots et l' expansion des noms de chemin .la source
for
boucle sera - de loin - la plus lente. Les deux autres méthodes seront très proches l'une de l'autre.xargs
: au moins la version GNU a une--arg-file
option (forme courte-a
). On pourrait donc faire à laxargs -a large_file_list -rd'\n' gzip -d
place. En effet, il n'y a pas de différence, mis à part le fait qu'il<
est un opérateur shell et feraitxargs
lire depuis stdin (qui shell "lie" au fichier), tout en-a
ferait ouvrirxargs
explicitement le fichier en questionparallel
de plusieurs copies degzip
, maisxargs
(au moins celui de GNU), a aussi le-P
commutateur pour cela. Sur les machines multicœurs, cela pourrait faire la différence. Mais il est également possible que la décompression soit complètement liée aux E / S de toute façon.Je doute que cela importerait beaucoup.
J'utiliserais une boucle, juste parce que je ne sais pas combien de fichiers sont répertoriés dans le fichier de liste, et je ne sais pas (généralement) si l'un des noms de fichiers a des espaces dans leurs noms. Faire une substitution de commande qui générerait une très longue liste d'arguments peut entraîner une erreur «Liste d'arguments trop longue» lorsque la longueur de la liste générée est trop longue.
Ma boucle ressemblerait
Cela me permettrait en outre d'insérer des commandes pour traiter les données après la
gunzip
commande. En fait, selon ce que sont réellement les données et ce qui doit être fait avec elles, il peut même être possible de les traiter sans les enregistrer du tout:(où se
process_data
trouve un pipeline qui lit les données non compressées à partir de l'entrée standard)Si le traitement des données prend plus de temps que leur décompression, la question de savoir si une boucle est plus efficace ou non devient hors de propos.
Idéalement , je préférerais ne pas travailler sur une liste de noms de fichiers et utiliser plutôt un modèle de globbing de nom de fichier, comme dans
où
./*.gz
est un modèle qui correspond aux fichiers pertinents. De cette façon, nous ne dépendons pas du nombre de fichiers ni des caractères utilisés dans les noms de fichiers (ils peuvent contenir des sauts de ligne ou d'autres espaces, ou commencer par des tirets, etc.)En relation:
la source
Sur ces deux, celui avec tous les fichiers passés à une seule invocation de
gzip
sera probablement plus rapide, précisément parce que vous n'avez besoin de lancergzip
qu'une seule fois. (Autrement dit, si la commande fonctionne, consultez les autres réponses pour les mises en garde.)Mais je voudrais rappeler la règle d'or de l'optimisation : ne le faites pas prématurément.
N'optimisez pas ce genre de chose avant de savoir que c'est un problème.
Cette partie du programme prend-elle du temps? Eh bien, la décompression de gros fichiers pourrait le faire, et vous devrez le faire de toute façon, donc ce ne sera peut-être pas si facile de répondre.
Mesure. Vraiment, c'est le meilleur moyen d'en être sûr.
Vous verrez les résultats de vos propres yeux (ou avec votre propre chronomètre), et ils s'appliqueront à votre situation, ce que les réponses aléatoires sur Internet pourraient ne pas faire. Mettez les deux variantes dans des scripts et exécutez
time script1.sh
, ettime script2.sh
. (Faites cela avec une liste de fichiers compressés vides pour mesurer la quantité absolue de la surcharge.)la source
Quelle est la vitesse de votre disque?
Cela devrait utiliser tous vos processeurs:
Votre limite sera donc probablement la vitesse de votre disque.
Vous pouvez essayer de régler avec
-j
:Cela exécutera la moitié des travaux en parallèle comme la commande précédente et stressera moins votre disque, donc cela peut être plus rapide en fonction de votre disque.
la source