Grep -E,Sed -E - 使用 '[x]{1,9999}' 时性能低下,但为什么呢?

Grep -E,Sed -E - 使用 '[x]{1,9999}' 时性能低下,但为什么呢?

grepsed与选项一起使用--extended-regexp并且模式{1,9999}是所用正则表达式的一部分时,这些命令的性能会变低。为了更清楚起见,下面应用了一些测试。[1] [2]

  • grep -Eegrep和的相对性能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       

造成这种显著绩效差异的原因是什么?

答案1

请注意,耗时不是匹配,而是 RE 的构建。您会发现它也占用了相当多的 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

分配的次数似乎与迭代次数大致成比例,但分配的内存似乎呈指数增长。

这取决于 GNU 正则表达式的实现方式。如果您grep使用编译 GNU CPPFLAGS=-DDEBUG ./configure && make,并运行这些命令,您将看到指数效应。更深入地研究将意味着要学习大量有关 DFA 的理论,并深入研究 gnulib 正则表达式的实现。

在这里,您可以使用 PCRE,它似乎没有同样的问题:(grep -Po '[0-9]{1,65535}'最大值,尽管您总是可以执行[0-9](?:[0-9]{0,10000}){100}1 到 1,000,001 次重复之类的操作)不会比 花费更多的时间和内存grep -Po '[0-9]{1,2}'

相关内容