Lorsque grep
ou sed
sont utilisés avec l'option _--extended-regexp
_ et que le modèle _{1,9999}
_ fait partie de l'expression rationnelle utilisée, les performances de ces commandes deviennent faibles. Pour être plus clair, vous trouverez ci-dessous quelques tests . [1][2]
grep -E
_, egrep
et _sed -E
_ est presque égale, de sorte que seuls les tests effectués avec grep -E
sont fournis.Test 1
_$ time grep -E '[0-9]{1,99}' < /dev/null
real 0m0.002s
_
Test 2
_$ time grep -E '[0-9]{1,9999}' < /dev/null
> real 0m0.494s
_
Test 3
$ time grep -E '[0123456789] {1,9999}' </dev/null[.____.HERH> Réel 21m43.947s
Test 4
_$ time grep -E '[0123456789]+' < /dev/null
$ time grep -E '[0123456789]*' < /dev/null
$ time grep -E '[0123456789]{1,}' < /dev/null
$ time grep -P '[0123456789]{1,9999}' < /dev/null
real 0m0.002s
_
Quelle est la raison de cette différence significative de la performance?
Notez que ce n'est pas le jumelage qui prend du temps, mais la construction de l'ER. Vous constaterez qu'il utilise beaucoup de RAM:
$ valgrind grep -Eo '[0-9]{1,9999}' < /dev/null
==6518== HEAP SUMMARY:
==6518== in use at exit: 1,603,530,656 bytes in 60,013 blocks
==6518== total heap usage: 123,613 allocs, 63,600 frees, 1,612,381,621 bytes allocated
$ valgrind grep -Eo '[0-9]{1,99}' < /dev/null
==6578== in use at exit: 242,028 bytes in 613 blocks
==6578== total heap usage: 1,459 allocs, 846 frees, 362,387 bytes allocated
$ valgrind grep -Eo '[0-9]{1,999}' < /dev/null
==6594== HEAP SUMMARY:
==6594== in use at exit: 16,429,496 bytes in 6,013 blocks
==6594== total heap usage: 12,586 allocs, 6,573 frees, 17,378,572 bytes allocated
Le nombre d'allocations semble à peu près proportionnel au nombre d'itérations, mais la mémoire allouée semble croître de façon exponentielle.
Cela dépend de la façon dont GNU regexps sont implémentés. Si vous compilez GNU grep
avec CPPFLAGS=-DDEBUG ./configure && make
et exécutez ces commandes, vous verrez l'effet exponentiel en action. Pour aller plus loin, cela impliquerait de passer par beaucoup de théorie sur DFA et de plonger dans la mise en œuvre de regexp gnulib.
Ici, vous pouvez utiliser des PCRE qui ne semblent pas avoir le même problème: grep -Po '[0-9]{1,65535}'
(maximum, bien que vous puissiez toujours faire des choses comme [0-9](?:[0-9]{0,10000}){100}
pendant 1 à 1 000 001 répétitions) n'en prend pas plus. temps ni mémoire que grep -Po '[0-9]{1,2}'
.