Когда grep
или sed
используются с опцией, --extended-regexp
а шаблон {1,9999}
является частью используемого регулярного выражения, производительность этих команд становится низкой. Чтобы быть более понятным, ниже применяются несколько тестов. [1] [2]
- Относительная производительность
grep -E
,egrep
иsed -E
почти равна, поэтому только тест , которые были сделаны сgrep -E
предусмотрены.
Тест 1
$ time grep -E '[0-9]{1,99}' < /dev/null
real 0m0.002s
Тест 2
$ time grep -E '[0-9]{1,9999}' < /dev/null
> real 0m0.494s
Тест 3
$ time grep -E '[0123456789] {1,9999}' </ dev / null > настоящий 21м43.947с
Тест 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
В чем причина этого значительного различия производительности?
command-line
grep
regex
pa4080
источник
источник
[0-9]+
)time grep -E '[0-9]{1,99}' </dev/null
противtime grep -E '[0-9]{1,9999}' </dev/null
. Даже без ввода вторая команда работает медленно (16.04). Как и следовало ожидать, опуская-E
и побег{
и}
ведешь себя так же и замену-E
с-P
не медленно (PCRE является другим двигателем). Самое интересное, насколько быстрее[0-9]
это чем.
,x
и даже[0123456789]
. С любым из них и{1,9999}
,grep
потребляет огромное количество оперативной памяти; Я не осмелился позволить этому бежать больше чем ~ 10 минут.{
}
они'
'
указаны ; оболочка передает их без измененийgrep
. Во всяком случае,{1,9999}
было бы очень быстрое и простое расширение скобки . Оболочка просто расширит его до1 9999
.ps
иtop
для проверкиgrep
был передан ожидаемый аргумент и то, что он неbash
потребляет много оперативной памяти и процессора. Я ожидаю,grep
иsed
оба используют функции регулярного выражения POSIX, реализованные в libc для соответствия BRE / ERE; Я не должен был говоритьgrep
конкретно о дизайне, за исключением того, чтоgrep
разработчики решили использовать эту библиотеку.time grep ... < /dev/null
, чтобы люди не связывали реальную проблему с данными, поступающими в систему,grep
и другими посторонними вещами.Ответы:
Обратите внимание, что это не согласование, которое требует времени, но создание RE. Вы обнаружите, что он также использует довольно много оперативной памяти:
Количество выделений кажется примерно пропорциональным количеству итераций, но выделенная память, кажется, растет в геометрической прогрессии.
Это зависит от того, как реализованы регулярные выражения GNU. При компиляции GNU
grep
сCPPFLAGS=-DDEBUG ./configure && make
, и выполнять эти команды, вы увидите , экспоненциальный эффект в действии. Если вы углубитесь в это, это будет означать, что вам придется пройти через много теории о DFA и погрузиться в реализацию gnulib regexp.Здесь вы можете использовать PCRE, которые, похоже, не имеют такой же проблемы:
grep -Po '[0-9]{1,65535}'
(максимум, хотя вы всегда можете делать что-то вроде[0-9](?:[0-9]{0,10000}){100}
от 1 до 1 000 001 повторений) не требует больше времени и памяти, чемgrep -Po '[0-9]{1,2}'
.источник
grep -Po '[0-9]{1,9999}
который, кажется, не проблема.sed -E
илиgrep -E
, но вawk
тоже имеет эту низкую производительность (о последней команде AWK). Может быть,awk
также не может использовать PCRE?