bash: boucle plus de 20000 files lent – pourquoi?

Une simple boucle sur beaucoup de files est à moitié aussi rapide sur un système que sur l'autre.

En utilisant bash, j'ai fait quelque chose comme

for * in ./ do something here done 

En utilisant "time", j'ai pu confirmer, que sur system2, le "quelque chose ici" -part fonctionne plus rapidement que sur system1. Néanless, la boucle entière sur le système 2 prend le double aussi longtime que sur system1. Pourquoi? … et comment puis-je l'accélérer?

Il existe environ 20000 (text) des files dans le directory. Réduire le nombre de files à environ 6000 accélère considérablement les choses. Ces résultats restnt identiques indépendamment de la méthode en boucle (en remplaçant "for * in" par une command de search ou même en mettant les noms de files dans un tableau en premier).

System1: Debian (dans un openvz-vm, à l'aide de reiserfs)
System2: Ubuntu (processeur natif, plus rapide que System1, Raid5 plus rapide, utilisant ext3 et ext4 – les résultats restnt les mêmes)

Jusqu'à présent, j'aurais dû exclure: le matériel (System2 devrait être beaucoup plus rapide), les logiciels userland (bash, grep, awk, trouvent les mêmes versions) et .bashrc (pas de configuration spiffy).

C'est donc le système de files? Puis-je tordre ext3 / 4 pour qu'il soit aussi rapide que reiserfs?

Merci pour vos recommandations!

Edit: Ok, vous avez raison, j'aurais dû fournir plus d'informations. Maintenant, je dois révéler le murmure de mon débutant mais ici nous allons:

  declare -a UIDS NAMES TEMPS ANGLEAS ANGLEBS ELEM=0 for i in *html do #get UID UID=${i%-*html} UIDS[$ELEM]=$UID # get Name NAME=`awk -F, '/"name":"/ { lines[last] = $0 } END { print lines[last] }' ${i} | awk '{ print $2 }'` NAME=${NAME##\[*\"} NAMES[$ELEM]=$NAME echo "getting values for ["$UID"]" "("$ELEM "of" $ELEMS")" TEMPS[$ELEM]=`awk -F, '/Temperature/ { lines[last] = $0 } END { print lines[last] }' ${i} | sed 's/<[^>]*>//g' | tr -d [:punct:] | awk '{ print $3 }'` ANGLEAS[$ELEM]=`awk -F, '/Angle A/ { lines[last] = $0 } END { print lines[last] }' ${i} | sed 's/<[^>]*>//g' | tr -d [:punct:] | awk '{ print $3 }'` ANGLEBS[$ELEM]=`awk -F, '/Angle B/ { lines[last] = $0 } END { print lines[last] }' ${i} | sed 's/<[^>]*>//g' | tr -d [:punct:] | awk '{ print $3 }'` ### about 20 more lines like these ^^^ ((ELEM++)) done 

Oui, le problème est que je dois lire le file 20 fois mais mettre le contenu du file dans une variable (FILE = ( cat $i )) supprime les déchirages de ligne et je ne peux plus utiliser awk …? Peut-être que j'ai essayé mal alors, si vous avez une suggestion pour moi, je serais reconnaissant.

Toujours: il rest le problème, que lire un file dans ce directory prend trop longtime …

Pour la question du matériel: eh bien, system1 fonctionne avec un matériel de plus de 5 ans, system2 a 2 mois. Oui, les spécifications sont très différentes (autres maps mères, processeurs, etc.), mais le système 2 est beaucoup plus rapide dans tous les autres aspects et les taux d'écriture / écriture bruts dans le système de files sont aussi rapides.

3 Solutions collect form web for “bash: boucle plus de 20000 files lent – pourquoi?”

Dépend de ce que vous faites exactement, mais oui, les filesystems ext sont lents lorsque vous avez beaucoup de files dans un seul directory. La division des files dans les sous-directorys numérotés est un moyen commun.

Il n'est pas nécessaire d'utiliser des arrays dans awk pour ce que vous faites. Vous ne semblez pas utiliser la virgule comme séparateur de champ puisque vous imprimez $0 .

AWK peut faire ce que vous avez fait et tr .

Il serait utile de voir à quoi ressemblent vos données.

Une approche pourrait être quelque chose comme ça (bien qu'il soit très laid à regarder):

 for f in *.html do read -r array1[i] array2[i] array3[i] array4[i] . . . <<< $( awk ' /selector1/ {var1 = $2} /selector2/ {split($0,temparray,"<[^>]*>"); split(temparray[2],temparray); var2 = gensub("[[:punct:]]","","g",a[3])} /selector3/ {split($0,temparray,"<[^>]*>"); split(temparray[2],temparray); var3 = gensub("[[:punct:]]","","g",a[3])} . . . END { print var1, var2, var3, var4 . . . }' "$f" ((i++)) done 

Avec les choix d'indices de tableau dans le script awk dicté par la disposition réelle de vos données. Il peut y avoir de meilleures approches, mais celle-ci élimine environ 1 600 000 process (20 000 files * 20 vars * 4 process / var) étant engendrés de sorte que seulement environ 20 000 (un par file) sont.

Vous n'avez pas dit quels types de time d'exécution vous aviez, mais avec cette optimization, il est peut-être assez rapide pour que vous puissiez étudier le problème dans votre système plus récent.

Votre description est si vague, il est difficile de vous donner des conseils. Quoi qu'il en soit, 20k files dans un seul directory est beaucoup, mais pas tellement.

Plusieurs fois, il est possible d'accélérer les choses en repensant ce que vous faites. Que se passe-t-il actuellement pendant votre boucle? Votre script doit-il lire 20 000 files 20 000 fois? Dans l'affirmative, est-ce qu'il serait possible de modifier votre script pour lire uniquement 20 000 files et faire 20 000 fois la comparaison? Je veux dire: 1) lire un file, 2) effectuer toutes les comparaisons possibles contre ce file, 3) passer au prochain file.

Vous avez mentionné les noms de files en ordre, mais qu'est-ce que cela signifie dans ce cas? Le script doit-il encore effectuer 20 000 * 20 000 opérations de lecture au lieu de 20 000 opérations de lecture?

  • Avertissement ReiserFS: reiserfs_get_unused_objectid: plus d'identifiants d'object
  • Alternative à ReiserFS pour stocker de nombreux petits files dans un bloc?
  • Les astuces du serveur de linux et windows, tels que ubuntu, centos, apache, nginx, debian et des sujets de rĂ©seau.