Скорость компиляции Perl + OOP (Несколько методов). Тупые тесты

Никто не делал, наверное, полноценное тестирование производительности всех или почти всех методов и подходов, реализующих объекты в перле. Никто не делал, и я не буду. 

Вместо этого я понаделал тупые тесты при помощи команды time perl myscript.pl. Просто для того, чтобы кое-что прояснить для себя.

1. Чистый перл, атрибуты в массиве 

Массивы в перле быстрые. Пробуем такой код:

Для проверки код почти всегда один и тот же:

Что показывает time:

real  0m0.029s
user      0m0.024s
sys       0m0.000s

2. Чистый перл, атрибуты в хеше

Хеши в перле медленные, медленнее, чем массивы, поэтому, возможно, если делать акцессоры на хеше, то будет медленнее. Пробуем:

Время выполнения:

real       0m0.033s
user      0m0.020s
sys       0m0.008s

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

3. Используем Mojo::Base

Mojo::Base — удивительно легковесная штука с очень простым, незамутненным синтаксисом, реализующая базовые возможности объектов. Давно хотел протестить, насколько велика цена синтаксического сахара Mojo::Base:

Код сократился, а время выполнения? Смотрим:

real       0m0.032s
user      0m0.024s
sys       0m0.000s

Вообще, в среднем, такой код получается сравним по скорости с предыдущим, или, если все же придираться, то чууууть-чуть медленнее. Но есть Mojo::Base::XS, который, возможно, решит такую проблему. Неожиданно приятно.

4. Используем Class::Struct

Class::Struct очень старый, но, тем не менее, очень известный модуль, к которому приложились довольно известные, именитые перл-программисты. Поэтому его было тоже интересно.

В итоге:

real       0m0.050s
user      0m0.012s
sys       0m0.016s

В целом медленнее, причем заметно. 

5. Используем Moose

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

Шок:

real       0m0.419s
user      0m0.320s
sys       0m0.032s

В заключение еще раз повторю, что тесты тупые, о производительности тех или иных решений можно судить относительно. Mojo::Base интересен и, на мой взгляд, нуждается в более взрослых сравнительных тестах. Но это в будущем. 

Mojolicious::Plugin::AnyData-1.20

В новой версии добавлены некоторые полезные функции, например, при повторной загрузке таблицы, предыдущая версия удаляется из памяти. Это сделано для того, чтобы не вызывать падение системы и иметь некий предсказуемый положительный результат. 

Загрузка таблиц теперь происходит в любом месте программы, благодаря новому хелперу any_data, который доступен теперь для вызова методов load_data и func в любом месте кода, как экшенов, так и темплейтов (хе-хе), а не только во время запуска приложения, как раньше.

Исправлены некоторые мелкие баги, добавлена/улучшена документация.

На гитхабе: https://github.com/shootnix/Mojolicious-Plugin-AnyData

На CPAN'e: http://search.cpan.org/~shootnix/Mojolicious-Plugin-AnyData-1.20/lib/Mojolicious/Plugin/AnyData.pm

По-прежнему, принимаются замечания или предложения для дальнейшего развития плагина. Заранее всем спасибо. 

Параметры функции в Perl, небольшая зарисовка

Если внутри функции использовать массив @_, то это повлияет на целостность данных вне функции:

Если из массива вынимать данные и использовать их, то с внешними переменными все будет в порядке:

Эту разницу нужно учитывать или даже использовать, кому как больше нравится.

Mojolicious::Plugin::AnyData

Какое-то время назад я, просматривая на досуге один фреймворк на джаве, был обрадован интересной фиче — возможности прямо из yaml'а грузить в память некоторые структурированные данные и работать с ними с помощью ORM (Hybernate, кажется) так, как будто это данные, взятые из базы данных.

Тогда я подумал, нет ли способа организовать что-то похожее для Mojolicious. Был найден годный модуль DBD::AnyData, осталось только сделать плагин. Помимо всего прочего, добавлено несколько методов (пока только два) для удобства пользования плагином. 

Ссылка: https://github.com/shootnix/Mojolicious-Plugin-AnyData. Модуль пока не публикую на спане, желая для начала собрать некоторое кол-во багрепортов и предложений по улучшению. Отсюда просьба: критикуйте, замечайте, высказывайтесь, буду очень рад любому фидбэку. Ну и от посильной помощи не откажусь ;-)

Динамические грабли Perl

Известно, что Perl — динамический язык. Кроме всего прочего это означает создание переменных «на лету». Бороться с внезапно созданными переменными из-за простой опечатки мы знаем как — use strict. 

Но динамически создаются, как мы знаем, не только переменные, но и ключи хэша или ссылки на хэш, в этом случае use strict не помогает.

Допустим такую задачу: у вас есть массив, из которого нужно взять пять элементов. В качестве элементов у нас — хэш. Задача решается просто:

Думаю, объяснять этот пример не нужно, однако, есть условие, которое довольно просто не заметить: что, если $arrayref был изначально пуст? Что станет с ним после этих манипуляций? Правильно, он будет заполнен! 

В данном конкретном случае Perl заполнит $arrayref пустыми хэшами, которые создались динамически при помощи вызова $arrayref->[$i]->{somekey}.

Что делать, если это не входит в наши планы? Самый простой и надежный способ, конечно, следить внимательно за всем самому, не допуская подобного со стороны Perl'a. Но, немного порывшись на спане, было найдено решение для тех, кто ценит заботу о своем коде со стороны автоматических программ и решений:

Теперь прагма будет следить за тем, чтобы Perl не бесчинствовал почем зря, создавая динамически ненужные хэши.

Игра с условиями в Perl

Например, такая задача. У нас есть переменная, в которую нужно поместить или значение по-умолчанию или значение из функции. Функция возвращает или значение, или undef. В дополнение ко всему, есть два замечания:

1. Функция или вызывается или нет, т.е. это дополнительное условие.

2. Переменная должна _всегда_ иметь положительное значение, т.е., если функция возвратит undef, нужно поместить в нее значение по-умолчанию.

Вариантов решения много. Самый простой вариант напрашивается еще до того, как прочитаешь задачу до конца.

Недостаток только один: нужно еще проверить, что содержит $value на выходе и присвоить значение по-умолчанию, если там undef.

Конечно, этот вариант быстро правится на такой:

Тут в случае, если function() вернет undef, мы имеем возможность подкорректировать значение переменной «на лету». Немного смущает такое количество строк в решении, в сущности, тривиальной задачи, поэтому перепишем с использованием тернарного оператора:

Все хорошо, однако выглядит по-прежнему не очень из-за повторяющихся кусков. Подумав, решение приходит:

Как получить массив определенной длины из элементов другого, рандомно?

Задача: есть массив, например, ['a'..'z']. Нужно софрмировать из элементов этого массива другой массив, заданной длины. 

Одно важное замечание: элементы в новом массиве не должны повторяться. И еще: получить элементы нужно рандомно.

Подсветка синтаксиса в posterous

На самом деле, подсветка синтаксиса не нужна, постерус поддерживает gist, нужно просто поставить линк в нужное место и всего делов.

1. Создать гист на gist.github.com

2. Вставить прямую ссылку на gist внутрь поста. 

3. Профит!