Модераторы: ginnie
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> угадайте, какая регулярка быстрее? 
:(
    Опции темы
zyxerr
Дата 12.12.2008, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 17.7.2008

Репутация: нет
Всего: 2



$string = "Мама мыла раму";

1) /Мама/;
2) /^Мама/;
3) /^..../';

угадайте, какая регулярка работает быстрее?
PM MAIL   Вверх
ginnie
Дата 12.12.2008, 13:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 1
Всего: 49



Код

perl -e 'use re "debug"; $_="Mama myla ramu"; /Mama/; /^Mama/; /^..../;'
Compiling REx `Mama'
size 3 Got 28 bytes for offset annotations.
first at 1
rarest char M at 0
   1: EXACT <Mama>(3)
   3: END(0)
anchored "Mama" at 0 (checking anchored isall) minlen 4
Offsets: [3]
        1[4] 0[0] 5[0]
Compiling REx `^Mama'
size 4 Got 36 bytes for offset annotations.
first at 2
rarest char M at 0
   1: BOL(2)
   2: EXACT <Mama>(4)
   4: END(0)
anchored "Mama" at 0 (checking anchored) anchored(BOL) minlen 4
Offsets: [4]
        1[1] 2[4] 0[0] 6[0]
Compiling REx `^....'
size 6 Got 52 bytes for offset annotations.
first at 2
   1: BOL(2)
   2: REG_ANY(3)
   3: REG_ANY(4)
   4: REG_ANY(5)
   5: REG_ANY(6)
   6: END(0)
anchored(BOL) minlen 4
Offsets: [6]
        1[1] 2[1] 3[1] 4[1] 5[1] 6[0]
Omitting $` $& $' support.

EXECUTING...

Guessing start of match, REx "Mama" against "Mama myla ramu"...
Found anchored substr "Mama" at offset 0...
Guessed: match at offset 0
Guessing start of match, REx "^Mama" against "Mama myla ramu"...
Guessed: match at offset 0
Matching REx "^Mama" against "Mama myla ramu"
  Setting an EVAL scope, savestack=3
   0 <> <Mama myla ra>    |  1:  BOL
   0 <> <Mama myla ra>    |  2:  EXACT <Mama>
   4 <Mama> < myla ra>    |  4:  END
Match successful!
Matching REx "^...." against "Mama myla ramu"
  Setting an EVAL scope, savestack=3
   0 <> <Mama myla ra>    |  1:  BOL
   0 <> <Mama myla ra>    |  2:  REG_ANY
   1 <M> <ama myla ra>    |  3:  REG_ANY
   2 <Ma> <ma myla ra>    |  4:  REG_ANY
   3 <Mam> <a myla ra>    |  5:  REG_ANY
   4 <Mama> < myla ra>    |  6:  END
Match successful!
Freeing REx: `"Mama"'
Freeing REx: `"^Mama"'
Freeing REx: `"^...."'


Судя по выводу быстрее должен быть первый вариант.


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
zyxerr
Дата 12.12.2008, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 17.7.2008

Репутация: нет
Всего: 2



Код

use Benchmark;

$string = "Мама мыла раму";

timethese(1000000,{
    '1' => '$string=~ m/Мама/;',
    '2' => '$string=~ m/^Мама/;',
    '3' => '$string=~ m/^..../',

});
<>

у меня вышло:
самый быстрый /Мама/
немного медленней /^..../
совсем медленный /^Мама/ (в два раза медленнй первого варианта)
.
и это странно, ведь "Мама" находится в начале строки и указание якоря по идее должно увеличивать скорость обработки, а оно наоборот - замедляет в два раза. Странно. Кстати, даже одна круглая скобка /(Мама)/ замедляет скорость в два раза. И указание модификатора /мама/i замедляет прилично.
.
если искать шаблоны
1) /Мама/
2) /мыла/ 
3) /раму/
быстрее всего ищется в начале строки (ну это вполне ожидаемо)


Это сообщение отредактировал(а) zyxerr - 12.12.2008, 13:36
PM MAIL   Вверх
zyxerr
Дата 12.12.2008, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 17.7.2008

Репутация: нет
Всего: 2



вот такой еще тест (подобный пример часто Фридл приводит, говоря об оптимизации записи):

$string= "that cat is sad";

1) /that|this|those/
2) /th(at|is|ose)/
3) /th(?:at|is|ose)/

какая регулярка быстрее?
по Фридлу вариант 3 должен быть намного быстрее варианта 1, но он быстрее всего на 2-3%
места распределились:
/th(?:at|is|ose)/ - самый быстрый
/that|this|those/ - уступает пару процентов (но при этом легче читается)
/th(at|is|ose)/ - самый медленный (за счет сохранения переменной $1)
.
обнаружил интересную вещь:
Strawbery Perl версии 5.10 МЕДЛЕННЕЕ В ТРИ РАЗА чем Active State Perl 5.8 (других версий у меня нет)


Это сообщение отредактировал(а) zyxerr - 12.12.2008, 14:03
PM MAIL   Вверх
amg
Дата 12.12.2008, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: нет
Всего: 50



Цитата(zyxerr @  12.12.2008,  13:36 Найти цитируемый пост)
и это странно, ведь "Мама" находится в начале строки и указание якоря по идее должно увеличивать скорость обработки
Видимо, когда-то давно так оно и было (по крайней мере, мне опытные люди рекомендовали использовать ^ и $ для ускорения). Потом (пару лет назад) проверил -- ускорение есть, но совсем незначительное. А сейчас, судя по Вашим и ginnie данным, уже наоборот.  

Кстати, попробуйте померить скорость с модификатором /g
PM MAIL   Вверх
zyxerr
Дата 12.12.2008, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 17.7.2008

Репутация: нет
Всего: 2



в первом тесте (Мама мыла раму) разница между Strawberry 5.10 и Active State 5.8 - почти в два раза в пользу последнего.

Добавлено @ 14:28
amg, тест с модификатором g:

Код

$string = "Мама мыла раму мама мыла раму мама мыла раму"; 
timethese(10000000,{
    '1' => '$string=~ m/а/;',
    '2' => '$string=~ m/а/g;',
    '3' => '$string=~ m/а/gi;',
});
<>


второй вариант медленней на 40% (буква "а"  встречается 12  раз в строке)
третий вариант медленней на 80%


Это сообщение отредактировал(а) zyxerr - 12.12.2008, 14:46
PM MAIL   Вверх
amg
Дата 12.12.2008, 14:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: нет
Всего: 50



Цитата(zyxerr @  12.12.2008,  14:18 Найти цитируемый пост)
тест с модификатором g:

Код
$string = "Мама мыла раму мама мыла раму мама мыла Раму"; 
timethese(10000000,{
  '1' => '$string=~ m/Раму/;',
  '2' => '$string=~ m/Раму/g;',
});
А в этом случае /g ускоряет поиск.
PM MAIL   Вверх
zyxerr
Дата 12.12.2008, 14:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 17.7.2008

Репутация: нет
Всего: 2



amg, мне кажется, это потому, что поиск БЕЗ /g идет слева направо, а с /g - справа налево. 

Код

$string = "Раму Мама мыла раму мама мыла раму мама мыла"; 
timethese(10000000,{
  '1' => '$string=~ m/Раму/;',
  '2' => '$string=~ m/Раму/g;',
});
 


здесь наоборот - второй вариант с /g медленней работает.

Добавлено @ 15:04
если мы поставим "Раму" в середину: $string = "Мама мыла раму Раму раму мама мыла";  
то все равно, модификатор /g замедляет поиск на 40%.
.
ИТОГ: поиск с модификатором /g начинается с конца строки. Если искомое слово стоит в конце, то добавление модификатора /g ускоряет поиск

Это сообщение отредактировал(а) zyxerr - 12.12.2008, 15:06
PM MAIL   Вверх
tolkien
Дата 13.12.2008, 00:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 277
Регистрация: 5.4.2008

Репутация: нет
Всего: 4



zyxerr
Лучше не зацикливаться на этом деле. Тем более ваши выше варианты не совсем корректны. Результат их работы в другом случаи(когда Мама будет в середине строки или в конце) будет совершенно разный. И не в плане производительности. Что есть существенное различие. Поэтому для корректной оценке нужно брать только такие регулярные выражения которые на всех входных данных будут давать одинаковый результат на выходе. Тогда и можно будет сравнивать производительность. 
В соседнем топике qcc хорошо написал насчет оптимизации. Что он сначала делает работоспособный код и уж потом если требуется его оптимизацию. 
PM MAIL   Вверх
ginnie
Дата 14.12.2008, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 1
Всего: 49



Уважаемый amg, не хочу Вас огорчать, но придется:

Код

#!/usr/bin/perl
use strict;

my $string = 'test message not defined';

sub test1 {
        $string =~ /message/;
}

sub test2 {
        $string =~ /message/g;
}

print 'test1:', $/;
for my $counter (1..5) {
        print(test1() ? 'true' : 'false', $/);
}
print test2:', $/;
for my $counter (1..5) {
        print(test2() ? 'true' : 'false', $/);
}


Код

test1:
true
true
true
true
true
test2:
true
false
true
false
true


Добавлено через 2 минуты и 4 секунды
Цитата(zyxerr @  12.12.2008,  14:58 Найти цитируемый пост)
мне кажется, это потому, что поиск БЕЗ /g идет слева направо, а с /g - справа налево. 

Perl так не умеет smile Поиск всегда производится слева направо. 


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
amg
Дата 15.12.2008, 08:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: нет
Всего: 50



Цитата(ginnie @  14.12.2008,  14:46 Найти цитируемый пост)
Уважаемый amg, не хочу Вас огорчать, но придется:
Нда, получается, что предыдущие тесты m//g были некорректны, нужно было что-то вроде
pos($string) = undef; $string=~ m/Раму/g;
а это много медленнее.

PM MAIL   Вверх
zyxerr
Дата 15.12.2008, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 17.7.2008

Репутация: нет
Всего: 2



зы

Это сообщение отредактировал(а) zyxerr - 15.12.2008, 10:47
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Регулярные выражения | Следующая тема »


 




[ Время генерации скрипта: 0.0822 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.