这是出于好奇而不是其他原因,因为我无法在Google上找到有关此功能的任何有用信息(CORE::substcont)

在剖析和优化一些旧的,缓慢的XML解析代码时,我发现以下正则表达式每次执行该行时都会调用substcont 31次,并花费了大量时间:


  $handle =~s/(>)\s*(<)/$1\n$2/g;
  # spent  1.09s making 310000 calls to main::CORE:substcont, avg 4µs/call
  # spent  58.8ms making  10000 calls to main::CORE:subst, avg 6µs/call

与前一行相比:


  $handle =~s/(.*)\s*(<\?)/$1\n$2/g;
    # spent   136ms making 10000 calls to main::CORE:subst, avg 14µs/call
    # spent  84.6ms making 20000 calls to main::CORE:substcont, avg 4µs/call

substcont调用的数量非常令人惊讶,尤其是因为我认为第二个正则表达式会更昂贵。显然,这就是为什么分析是一件好事的原因;-)

随后,我更改了这两行,以删除不必要的backrefs,从而为行为不佳的行带来了引人注目的结果:


$handle =~s/>\s*</>\n</g;
  # spent   341ms making 10000 calls to main::CORE:subst, avg 34µs/call
  • 所以,我的问题是-为什么原始文件要对substcont进行如此多的调用,substcont甚至在耗时如此长的正则表达式引擎中做什么?
  • 最佳答案

    substcont是Perl的“替代迭代器”的内部名称。与s///有关。根据我所掌握的信息,似乎在执行backref时会触发substcont。也就是说,当存在$1时。您可以使用B::Concise稍微玩一下。

    这是不带backref的简单正则表达式的操作码。

    $ perl -MO=Concise,-exec -we'$foo = "foo";  $foo =~ s/(foo)/bar/ig'
    1  <0> enter
    2  <;> nextstate(main 1 -e:1) v:{
    3  <$> const[PV "foo"] s
    4  <#> gvsv[*foo] s
    5  <2> sassign vKS/2
    6  <;> nextstate(main 1 -e:1) v:{
    7  <#> gvsv[*foo] s
    8  <$> const[PV "bar"] s
    9  </> subst(/"(foo)"/) vKS
    a  <@> leave[1 ref] vKP/REFC
    -e syntax OK
    

    和一个。
    $ perl -MO=Concise,-exec -we'$foo = "foo";  $foo =~ s/(foo)/$1/ig'
    1  <0> enter
    2  <;> nextstate(main 1 -e:1) v:{
    3  <$> const[PV "foo"] s
    4  <#> gvsv[*foo] s
    5  <2> sassign vKS/2
    6  <;> nextstate(main 1 -e:1) v:{
    7  <#> gvsv[*foo] s
    8  </> subst(/"(foo)"/ replstart->9) vKS
    9      <#> gvsv[*1] s
    a      <|> substcont(other->8) sK/1
    b  <@> leave[1 ref] vKP/REFC
    -e syntax OK
    

    这就是我所能提供的。您可能想尝试Rx,它是mjd的旧正则表达式调试器。

    09-28 03:17