Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 20/04/2020, à 12:40

Hizoka

[Retour d'experience] Repeter une suite de caractère

Bonjour à vous smile

Pour un besoin d'un script, il me fallait dupliquer une suite de caractère pour avoir une liste d'au moins 101 éléments.
Chaque élément pouvant être contenir plusieurs caractères.

J'ai donc fait mes petites commandes puis j'ai cherché sur le net pour voir comment faire mieux.
J'ai testé tout ce que j'ai trouvé mais si vous avez des remarques ou d'autres idées... smile
Et quitte à avoir fait tous ces tests, autant les partager, alors voilà...

Pour info :

Bash : GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
Processeur : 4 x Intel Corde 2 Quad CPU Q9550 @ 2.83GHz
Ram : 8Go

Protocole :
J'ai exécuté 10 000 fois chaque commande via une boucle for :

for x in {0.10000}; do ...; done

J'ai chronométré 3 fois la boucle ci-dessus et j'ai gardé la valeur médiane.

ce qui donne :

# Boucle qui chronomètre 3 fois
for a in {1..3}
do
    # Boucle lançant 10 000 la commande
    time for x in {0..10000}
    do
        # Commande(s) testé(s)
        unset Effect
        for y in {0..26}
        do
            Effect+=(a b c d)
        done
    done
done

Afin de gagner du temps de lecture, je les ai trié du plus rapide au plus lent.

Nouveau gagnant : 0,781s

printf -vEffect 'a b c d %.s' {0..25}
Effect=(${Effect})

Nouveau gagnant : 1,107s

for y in {0..25}
do 
     Effect+='a b c d '
done
Effect=(${Effect})

La plus rapide : 1,489s
Et ce, malgré ce que j'ai pu lire disant que {0..25} étant une sous boucle ça ralentissait la boucle for.

unset Effect
for y in {0..25}
do
    Effect+=(a b c d)
done

En modifiant un peu la boucle :
2,057s

unset Effect
y=26
while (( y-- ))
do
    Effect+=(a b c d)
done

2,175s

unset Effect
for ((i=0; i<=25; i++))
do
    Effect+=(a b c d)
done

2,320s

unset Effect
while [[ ${#Effect[@]} -le 100 ]]
do
    Effect+=(a b c d)
done

2,475s

unset Effect x
until [[ $[x+=1] -gt 26 ]]
do
    Effect+=(a b c d)
done

En s'éloignant de bash pur :
12.468s

Effect=$(printf "%26s") 
Effect=(${Effect// /a b c d })

13,163s

Effect=($(printf 'a b c d %.0s' {0..25}))

14,435s

Effect=($(echo -e ''$_{1..26}'\ba b c d '))

17,540s

unset Effect
for y in $(seq 0 25)
do
    Effect+=(a b c d)
done

0m24,594s

for a in {1..3}
do
    time for x in {0..10000}
    do
        Effect=($(utfout "a b c d " -r 24))
    done
done

28,741s

for a in {1..3}
do
    time for x in {0..10000}
    do
        Effect=$(utfout "a b c d " -r 24)
        Effect=(${Effect})
    done
done

Avec awk :
30,101s

Effect=($(awk 'BEGIN {
  while (z++ < 26) printf "a b c d "
}'))

30,230s

Effect=($(awk 'BEGIN {
OFS = "a b c d "
NF = 26
print
}'))

Autres tests horriblement longs :
54,661s

Effect=($(seq -f'a b c d %.0f' 101 | tr -d '\n0123456789'))

1m4,099s

Effect=$(printf "%26s") 
Effect=($(sed "s/ /a b c d /g" <<< "${Effect}"))

2m20,910s

Effect=($(python -c 'print "a b c d "*(26)'))

6m9,799s

Effect=($(seq 1 26 | xargs -I {} printf "a b c d "))

Dernière modification par Hizoka (Le 21/04/2020, à 17:08)


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#2 Le 20/04/2020, à 14:26

bruno

Re : [Retour d'experience] Repeter une suite de caractère

Salut,

Je ne comprends pas ton test.

Avec une boucle for :

time for y in {0..999}; do printf 'a b c d '; done

real    0m0,014s
user    0m0,009s
sys     0m0,005s

Avec une commande printf

time printf 'a b c d %.0s' {0..999}

real    0m0,003s
user    0m0,003s
sys     0m0,000s

#3 Le 20/04/2020, à 18:25

kamaris

Re : [Retour d'experience] Repeter une suite de caractère

Oui, un unique printf est certainement une bonne idée, mais tout est dans l'affectation de variable après.

Si on fait

Effect=$(printf 'a b c d %.s' {0..26})

ça sera bien plus lourd que les meilleures versions de Hizoka.
En gros, j'obtiens les mêmes temps pour une boucle en x à 1000 unités au lieu de 10000.

Par contre, si on fait

printf -vEffect 'a b c d %.s' {0..26}

là, ça marche bien : j'ai une réduction d'un bon facteur 7.

Hors ligne

#4 Le 20/04/2020, à 18:36

bruno

Re : [Retour d'experience] Repeter une suite de caractère

Je ne comprends toujours pas wink

time for y in {0..999}; do Effect+='a b c d '; done       

real    0m0,012s
user    0m0,011s
sys     0m0,000s
time Effect=$(printf 'a b c d %.0s' {0..999})

real    0m0,007s
user    0m0,005s
sys     0m0,000s

Le problème ne serait-il pas au niveau de la méthode de test ?

#5 Le 20/04/2020, à 19:06

kamaris

Re : [Retour d'experience] Repeter une suite de caractère

Pas vraiment, non : ça dépend plutôt de la taille de la chaine à engendrer.
Tu es parti sur 1000 répétitions de la chaine de base, alors que Hizoka partait sur 26 (ou 27) répétitions : je pense qu'il faut prendre ça comme une donnée.
Car si on augmente le nombre de répétitions, la rapidité de printf finit par l'emporter, mais pour un petit nombre de répétitions, ça n'est pas le cas :

$ time Effect=$(printf 'a b c d %.s' {0..26})

real	0m0,005s
user	0m0,000s
sys	0m0,005s
$ unset Effect; time for y in {0..26}; do Effect+='a b c d '; done

real	0m0,000s
user	0m0,000s
sys	0m0,000s
$ 

D'où l'intérêt de mettre une boucle en x autour de ça ensuite, pour faire monter les temps et pouvoir mieux comparer :

$ f() { time for x in {0..1000}; do unset Effect; Effect=$(printf 'a b c d %.s' {0..26}); done }
$ g() { time for x in {0..1000}; do unset Effect; for y in {0..26}; do Effect+='a b c d'; done; done }
$ h() { time for x in {0..1000}; do unset Effect; printf -vEffect 'a b c d %.s' {0..26}; done }
$ f

real	0m4,175s
user	0m1,156s
sys	0m3,067s
$ g

real	0m0,239s
user	0m0,223s
sys	0m0,000s
$ h

real	0m0,104s
user	0m0,095s
sys	0m0,000s
$ 

Hors ligne

#6 Le 20/04/2020, à 19:29

Hizoka

Re : [Retour d'experience] Repeter une suite de caractère

Pas mal en effet smile
0,781s   

for a in {1..3}
do
    time for x in {0..10000}
    do
        printf -vEffect 'a b c d %.s' {0..25}
        Effect=(${Effect})
    done
done

@bruno
Je fais mes tests sur 10 000 boucles, pas 1 000.
Je vois que la création d'une liste est plus lourde que celle d'une variable.


0,515s

for a in {1..3}
do
    time for x in {0..10000}
    do
        unset Effect
        for y in {0..25}
        do 
            Effect+='a b c d '
        done
    done
done

Si on fait sans liste.


1,107s

for a in {1..3}
do
    time for x in {0..10000}
    do
        unset Effect
        for y in {0..25}
        do 
            Effect+='a b c d '
        done
        Effect=(${Effect})
    done
done

Si on fait une variable puis une liste


1,455s

for a in {1..3}
do
    time for x in {0..10000}
    do
        unset Effect
        for y in {0..25}
        do 
            Effect+=(a b c d)
        done   
    done
done

Si on fait une liste directement

Dernière modification par Hizoka (Le 21/04/2020, à 17:05)


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#7 Le 21/04/2020, à 14:56

LeoMajor

Re : [Retour d'experience] Repeter une suite de caractère

une suite de caractère pour avoir au moins 101 caractères.

bonjour,

lapsus concernant l'hypothèse de départ.

:~$ t=$(utfout "abcd" -r24)
:~$ wc -m <<<"$t"
101
for a in {1..3}
do
    time { e=$(utfout "abcd" -r 24); effect=$(utfout "$e" -r 10000); }
    time { e=$(utfout "a b c d " -r 25); effect=$(utfout "$e" -r 10000); }
done
real	0m0.623s
user	0m0.118s
sys	0m1.106s

real	0m1.267s
user	0m0.317s
sys	0m2.180s

real	0m0.661s
user	0m0.134s
sys	0m1.162s

real	0m1.228s
user	0m0.260s
sys	0m2.170s

real	0m0.621s
user	0m0.110s
sys	0m1.108s

real	0m1.345s
user	0m0.350s
sys	0m2.299s

Hors ligne

#8 Le 21/04/2020, à 17:02

Hizoka

Re : [Retour d'experience] Repeter une suite de caractère

J'ai modifié l'intro qui n'était peut être pas assez claire :

...il me fallait dupliquer une suite de caractère pour avoir une liste d'au moins 101 éléments.
Chaque élément pouvant être contenir plusieurs caractères.

0m24,594s

for a in {1..3}
do
    time for x in {0..10000}
    do
        Effect=($(utfout "a b c d " -r 24))
    done
done

28,741s

for a in {1..3}
do
    time for x in {0..10000}
    do
        Effect=$(utfout "a b c d " -r 24)
        Effect=(${Effect})
    done
done

KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#9 Le 21/04/2020, à 18:46

kamaris

Re : [Retour d'experience] Repeter une suite de caractère

Je pense que tu trouveras difficilement mieux que le couple

printf -v var … ; var=($var)

printf est une primitive du shell, qui gère son affectation de variable en interne.
Quant à la mise en tableau, cette forme est plus rapide que

read -a var <<<"$var"

qui est plus rapide que

mapfile -td' ' var <<<"$var"

Hors ligne

#10 Le 21/04/2020, à 19:31

Hizoka

Re : [Retour d'experience] Repeter une suite de caractère

C'est pas mal en effet smile

Merci !


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne