[Moscow.pm] tie Berkeley. Разобрался!!!

Ruslan Zakirov ruz на bestpractical.com
Ср Окт 24 07:02:44 PDT 2012


2012/10/24 ksvs <ksvs1996 на ymail.com>:
>
> Разобрался!!!
>
> Оказывается, в отличие от обычных хешей, для tied хешей вызов
> scalar keys %foo не оптимизирован. Поэтому вместо того, чтобы просто вернуть количество записей, идет перебор и подсчет всех.

Он не может быть оптимизирован со стороны perl core по очень тупой
причине - история.

1) $s = scalar %hash возвращает не количество эелементов, а
распределение в хеше. И по соображениям совместимости это не хотят
менять. В новых версиях используют сложный код определения boolean
контекста. Теперь if (%h) работает быстрее чем if (keys %h) или так же
быстро, но только в определенных конструкциях.
2) Для tied все иначе. Так-как keys реализовано через итератор, то нет
никакой возможности подсказать, что keys вызвано в скалярном
контексте. Единственная возможность вызывать какой-то новый метод на
tied объекте.
3) Новый метод на tied объекте - это полный гемор. Так как изначально
не было требования, что все tied объекты должны наследоваться от
какой-то базовой реализации, то введение любого нового метода
сопряжено с гемором высокого маштаба. То есть if
($tied_obj->can("SCALAR_KEYS")) { ... } else { код эмулятор }
4) Метод SCALAR как раз из таких поздних и делается проверка.
5) Что самое интересное. Если метода SCALAR нету, то дергается
итератор и если мы внутри итерации или есть первый элемент, то
возвращается true значение.
6) А вот если он есть, то он дергается. Получается, что если его нет
то scalar %tied может быть быстрее чем если он есть. Ведь из метода
SCALAR нельзя узнать вызваны мы в boolean или scalar контексте, а
значит всегда нужно вернуть полный ответ, например подсчитать
количество ключей.

Вот такие пироги.

tied magic работает, но только не там где нужна скорость.

Если все таки нужен tied, то нужно переходить на новые версии и всегда
использовать if (%h).

К сожалению в универсальном коде нельзя использовать:

my $s = %h;
if ($s) {...}
...
if ($s) {...}

Потому-что my $s = %h для обычных хешей медленный. Хорошо хоть это редко нужно.

> Читал, что в какой-то базе данных тоже так. или в Постгресс или ИнноДВ.

В InnoDB нет счетчика количества записей.

> Вот как оказывается, заменил одну строчку, а какой результат.
>
> Как только стал посчитывать сам - все залетало!
>
> Интересно, а много еще подводных камней в Perl?
>
> А если бы не использовал tie, а напрямую, то не потерял бы 4 дня!!!
>
> После этого задумаешься, а стоит смотреть на Moose и прочие штучки.
>
>
>
>
> ----- Original Message -----
> From: ksvs <ksvs1996 на ymail.com>
> To: Moscow.pm group <moscow-pm на pm.org>
> Cc:
> Sent: Tuesday, 23 October 2012, 9:07
> Subject: Re: [Moscow.pm] tie Berkeley
>
>> Даже интересно стало. Вот что я сделал:
>
>> https://gist.github.com/3933779
>> и убил свою ZFS на фряхе )))
>>
>> Она все же пишет на диск, не знаю куда, но много.
>> В gist'е последний результат которого я смог дождаться 1500000
>> элементов в хеше...
>>
>> А вот, когда я сделал
>> tie %h1, 'BerkeleyDB::Hash', -Cachesize => 700_000_000; # поставить
>> cache в 700Mb
>>
>> Процесс в памяти занял больше, но мучения диска начались только вот тут:
>>     100000      5378313/s      223696/s
>>     300000      5378313/s      231981/s
>>     700000      5474182/s      233712/s
>>   1500000      5296201/s      233712/s
>>   3100000      5064251/s      235469/s
>>   6300000      5420331/s      233712/s
>
> А я сделал замеры скорости программы от размера кеша:
> когда перловый кеш, то примерно О(1), когда Берклевский, то О(n)!
>
> Тю, а я не догадался, что можно Берклей без файла использовать.
> Просто сделал файл на /tmp, а /tmp у меня в памяти сделаны.
>
>
> P.S. У меня тоже FreeBSD :-)
>
> --
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org
>
> --
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org



-- 
Best regards, Ruslan.


Подробная информация о списке рассылки Moscow-pm