Wenn grep
oder sed
mit der Option verwendet werden --extended-regexp
und das Muster {1,9999}
Teil des verwendeten regulären Ausdrucks ist, wird die Leistung dieser Befehle gering. Um klarer zu sein, werden im Folgenden einige Tests angewendet. [1] [2]
- Die relative Leistung
grep -E
,egrep
undsed -E
ist fast gleich, so dass nur der Test, der mit gemacht wurdengrep -E
zur Verfügung gestellt.
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 > echte 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
Was ist der Grund für diesen signifikanten Leistungsunterschied?
command-line
grep
regex
pa4080
quelle
quelle
[0-9]+
time grep -E '[0-9]{1,99}' </dev/null
gegenübertime grep -E '[0-9]{1,9999}' </dev/null
. Auch ohne Eingabe ist der zweite Befehl langsam (am 16.04.). Wie erwartet ist das Weglassen-E
und Entkommen{
und}
das gleiche Verhalten und Ersetzen-E
durch-P
nicht langsam (PCRE ist eine andere Engine). Besonders interessant ist , wie viel schneller[0-9]
ist als.
,x
und sogar[0123456789]
. Bei jedem dieser und{1,9999}
,grep
verbraucht eine große Menge an RAM; Ich habe es nicht gewagt, es länger als ~ 10 Minuten laufen zu lassen.{
}
werden'
'
zitiert ; Die Shell übergibt sie unverändert angrep
. Auf jeden{1,9999}
Fall wäre eine sehr schnelle und einfache Klammererweiterung . Die Shell würde es einfach erweitern1 9999
.ps
undtop
überprüft, ob siegrep
übergeben wurden und dass sie nichtbash
viel RAM und CPU verbrauchen. Ich erwartegrep
undsed
beide verwenden die in libc implementierten POSIX-Regex-Funktionen für den BRE / ERE-Abgleich. Ich hätte eigentlich nicht speziell über Design sprechen sollen , es sei denn, die Entwickler haben sich für diese Bibliothek entschieden.grep
grep
time grep ... < /dev/null
, damit die Leute das eigentliche Problem nicht mit den eingespeisten Datengrep
und anderen irrelevanten Dingen in Konflikt bringen .Antworten:
Beachten Sie, dass nicht das Matching Zeit braucht, sondern der Aufbau des RE. Sie werden feststellen, dass es auch ziemlich viel RAM verbraucht:
Die Anzahl der Zuweisungen scheint ungefähr proportional zur Anzahl der Iterationen zu sein, aber der zugewiesene Speicher scheint exponentiell zu wachsen.
Das hängt davon ab, wie GNU-Regexps implementiert werden. Wenn Sie GNU
grep
mit kompilierenCPPFLAGS=-DDEBUG ./configure && make
und diese Befehle ausführen, sehen Sie den exponentiellen Effekt in Aktion. Tiefer zu gehen würde bedeuten, eine Menge Theorie über DFA durchzugehen und in die Implementierung von Gnulib Regexp einzutauchen.Hier können Sie stattdessen PCREs verwenden, die nicht das gleiche Problem zu haben scheinen:
grep -Po '[0-9]{1,65535}'
(das Maximum, obwohl Sie immer Dinge wie[0-9](?:[0-9]{0,10000}){100}
1 bis 1.000.001 Wiederholungen ausführen können ) benötigt weder mehr Zeit noch Speicher alsgrep -Po '[0-9]{1,2}'
.quelle
grep -Po '[0-9]{1,9999}
, die das Problem nicht zu haben scheint.sed -E
odergrep -E
aber inawk
auch hat diese geringe Leistung (über letzten awk - Befehl). Vielleichtawk
kann PCRE auch nicht verwendet werden?