为什么这个正则表达式调用substcont的次数过多?

时间:2010-05-24 16:52:25

标签: regex perl optimization profiling

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

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

  

呼叫:10000时间:2.65s子呼叫:320000潜艇时间:1.15s`

  $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

与上一行相比:

  

呼叫:10000时间:371ms子呼叫:30000潜艇时间:221ms

  $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调用的数量是非常令人惊讶的,特别是因为我认为第二个正则表达式会更昂贵。这显然是为什么剖析是一件好事; - )

我随后改变了这两行以删除不必要的背景,对于表现不佳的行有显着效果:

  

呼叫:10000时间:393ms子呼叫:10000次潜艇时间:341ms

$handle =~s/>\s*</>\n</g;
  # spent   341ms making 10000 calls to main::CORE:subst, avg 34µs/call
  • 所以,我的问题是 - 原来为什么要对substcont进行过多次调用,以及在正则表达式引擎中甚至做了多少甚至做什么呢?

1 个答案:

答案 0 :(得分:4)

substcont是Perl的“替换迭代器”的内部名称。与s///有关。基于我所拥有的少量信息,在进行反射时似乎会触发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的旧正则表达式调试器。