Почему это регулярное выражение вызывало subcont слишком много раз? - PullRequest
7 голосов
/ 24 мая 2010

Это больше из любопытства, чем что-либо еще, так как я не могу найти в Google полезную информацию об этой функции (CORE :: substcont)

При профилировании и оптимизации какого-то старого, медленного кода синтаксического анализа XML я обнаружил, что следующее регулярное выражение 31 раз вызывает substcont при каждом выполнении строки и занимает огромное количество времени:

Звонки: 10000 Время: 2,65 с Подзвонки: 320000 Время в абонентах: 1,15 с`

  $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 Время: 371 мс. Дополнительные вызовы: 30000 Время в абонентах: 221 мс

  $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

Количество вызовов subcont довольно удивительно, особенно если учесть, что я бы подумал, что второе регулярное выражение будет дороже. Именно поэтому профилирование - это хорошо; -)

Впоследствии я изменил обе эти строки, чтобы удалить ненужные ссылки, с драматическими результатами для строки с плохим поведением:

Звонки: 10000 Время: 393 мс Суб звонки: 10000 Время в сабвуферах: 341 мс

$handle =~s/>\s*</>\n</g;
  # spent   341ms making 10000 calls to main::CORE:subst, avg 34µs/call
  • Итак, мой вопрос - почему оригинал должен был делать так много обращений к substcont, и что subcont вообще делает в движке регулярных выражений, который занимает столько времени?

1 Ответ

4 голосов
/ 24 мая 2010

substcont - это внутреннее имя Perl для «итератора подстановки».Что-то связанное с s///.Судя по тому, что у меня мало информации, кажется, что substcont срабатывает при выполнении обратного вызова.То есть, когда $1 присутствует.Вы можете немного поиграть с ним, используя B :: Concise.

Вот коды операций простого регулярного выражения без обратного ссылки.

$ 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...