【问题标题】:How to measure regex re performance properly?如何正确测量正则表达式的性能?
【发布时间】:2019-07-16 21:36:08
【问题描述】:

尝试一些正则表达式性能测试(听到一些传言说 erlang 很慢)

>Fun = fun F(X) -> case X > 1000000 of true -> ok; false -> Y = X + 1, re:run(<<"1ab1jgjggghjgjgjhhhhhhhhhhhhhjgdfgfdgdfgdfgdfgdfgdfgdfgdfgdfgfgv">>, "^[a-zA-Z0-9_]+$"), F(Y) end end.
#Fun<erl_eval.30.128620087>
> timer:tc(Fun, [0]).                                                         
{17233982,ok}                                                                   
> timer:tc(Fun, [0]).   
{17155982,ok}

以及编译正则表达式后的一些测试

{ok, MP} = re:compile("^[a-zA-Z0-9_]+$").                                   
{ok,{re_pattern,0,0,0,                                                          
            <<69,82,67,80,107,0,0,0,16,0,0,0,1,0,0,0,255,255,255,
              255,255,255,...>>}}
> Fun = fun F(X) -> case X > 1000000 of true -> ok; false -> Y = X + 1, re:run(<<"1ab1jgjggghjgjgjhhhhhhhhhhhhhjgdfgfdgdfgdfgdfgdfgdfgdfgdfgdfgfgv">>, MP), F(Y) end end.               
#Fun<erl_eval.30.128620087>
> timer:tc(Fun, [0]).                                                         
{15796985,ok}                                                                   
>        
> timer:tc(Fun, [0]).
{15921984,ok}

http://erlang.org/doc/man/timer.html

除非另有说明,否则时间始终以毫秒为单位。

http://erlang.org/doc/man/re.html#compile-1

如果要在程序的生命周期内使用同一个表达式匹配多个主题,则在匹配之前编译正则表达式很有用。编译一次执行多次,比每次想匹配都要编译效率高得多。

问题

  1. 为什么它返回微秒?(应该是毫秒?)
  2. 编译正则表达式没有太大区别,为什么?
  3. 我应该编译它吗?

【问题讨论】:

    标签: regex performance erlang


    【解决方案1】:
    1. 在模块timer中,函数tc/2返回微秒
    tc(Fun) -> {Time, Value}
    tc(Fun, Arguments) -> {Time, Value}
    tc(Module, Function, Arguments) -> {Time, Value}
        Types
        Module = module()
        Function = atom()
        Arguments = [term()]
        Time = integer()
          In microseconds
        Value = term()
    
    1. 因为函数Fun需要在case 1中每次递归(100万次)编译字符串"^[a-zA-Z0-9_]+$"。相比之下,在case 2中你先编译。然后你把结果带入递归,所以这就是性能低于案例 1 的原因。

    运行(主题,RE)-> {匹配,捕获} |不匹配

    主题 = iodata() | unicode:charlist()

    RE = mp() | iodata()

    正则表达式可以指定为 iodata(),其中 如果它被自动编译(如 compile/2)并执行,或者 作为预编译的 mp() 在这种情况下,它是针对主题执行的 直接。

    1. 是的,您应该注意先编译,然后再将其引入递归

    【讨论】:

    • 第一个测试没有事先编译正则表达式,第二个测试采用 MP 而不是正则表达式(请重读问题),性能比案例 1 好大约 2 秒,不差
    • 关于以微秒为单位的时间,我知道我是怎么错过的,谢谢
    【解决方案2】:

    是的,您应该在尝试衡量性能之前编译代码。当您将代码键入 shell 时,代码将被解释,而不是编译成字节码。将代码放入模块时,我看到了很大的改进:

    7> timer:tc(Fun, [0]).
    {6253194,ok}
    8> timer:tc(fun foo:run/1, [0]).
    {1768831,ok}
    

    (这两个都带有已编译的正则表达式。)

    -module(foo).
    
    -compile(export_all).
    
    run(X) ->
        {ok, MP} = re:compile("^[a-zA-Z0-9_]+$"),
        run(X, MP).
    
    run(X, _MP) when X > 1000000 ->
        ok;
    run(X, MP) ->
        Y = X + 1,
        re:run(<<"1ab1jgjggghjgjgjhhhhhhhhhhhhhjgdfgfdgdfgdfgdfgdfgdfgdfgdfgdfgfgv">>, MP),
        run(Y).
    

    【讨论】:

      猜你喜欢
      • 2020-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多