Как вы знаете, Perl не имеет очень удобной поддержки объектно-ориентированного программирования.
Если вы хотите программировать с помощью классов, вам придется многое делать вручную.
Однако Perl обладает очень богатыми возможностями расширения, поэтому со временем появилось множество библиотек (пакетов), обеспечивающих поддержку классов, методов и свойств с синтаксисом разной степени удобства.
Но как оказалось, эти пакеты проигрывают в производительности по сравнению с ручной реализацией ООП-проектов.
Те.
с одной стороны ими приятно пользоваться, но с другой стороны они замедляют работу кода.
Мне всегда хотелось знать, насколько медленнее становится код и какие из этих пакетов стоит использовать, а какие нет. Поэтому я решил провести небольшое исследование.
Обзор пакетов ООП
Во-первых, давайте сделаем краткий обзор доступных ООП-пакетов для Perl. Просто Перл Без каких-либо пакетов класс Perl можно создать следующим образом:Rate moose_sig moose moosex vanilla moose_sig 104102/s -- -0% -0% -74% moose 104383/s 0% -- -0% -74% moosex 104592/s 0% 0% -- -74% vanilla 401924/s 286% 285% 284% --Тогда такой класс можно использовать следующим образом:
Rate moosex moose moose_sig vanilla moosex 8596/s -- -94% -94% -95% moose 148055/s 1622% -- -0% -17% moose_sig 148516/s 1628% 0% -- -17% vanilla 178254/s 1974% 20% 20% --лось Основы пакета лось идеи из Perl6. С его помощью создавать классы становится намного проще.
Предыдущий пример, переписанный с использованием Moose, будет выглядеть намного лучше:
Rate moosex moose_sig moose vanilla moosex 1503608/s -- -1% -1% -17% moose_sig 1517928/s 1% -- -0% -16% moose 1517928/s 1% 0% -- -16% vanilla 1815063/s 21% 20% 20% --Как видите, вам больше не нужно явно создавать метод. новый , и свойства теперь описываются гораздо проще и естественнее.
Но пока не все гладко.
Нам придется вручную распаковать параметр $self в каждом методе класса.
И в целом методы остались просто перловыми процедурами.
Хотелось бы, чтобы они больше походили на обычные методы.
Метод::Сигнатуры И тут нам на помощь приходит этот замечательный пакет: Метод::Сигнатуры .
Советую прочитать документацию по нему — там много приятных сюрпризов.
Это делает наш код еще лучше:
Subroutine Dog::method redefined at /opt/local/lib/perl5/site_perl/5.14.1/darwin-thread-multi-2level/Devel/Declare/MethodInstaller/Simple.pm line 17. Prototype mismatch: sub Dog::method: none vs (&) at /opt/local/lib/perl5/site_perl/5.14.1/darwin-thread-multi-2level/Devel/Declare/MethodInstaller/Simple.pm line 17.MooseX::Объявить Пытливые умы приверженцев Perl не остановились на этом, а пошли гораздо дальше и написали MooseX::Объявить .
Действительно замечательный комплект, если бы не один недостаток (об этом позже).
Теперь мы можем достичь полной нирваны в описании нашего класса.
Собака :
Rate moosex moosex_sig moose_sig moose vanilla moosex 8651/s -- -94% -94% -94% -95% moosex_sig 146152/s 1589% -- -1% -3% -18% moose_sig 148025/s 1611% 1% -- -2% -17% moose 150866/s 1644% 3% 2% -- -16% vanilla 179200/s 1971% 23% 21% 19% --
Производительность ООП-пакетов
Perl позволяет добиться практически полной естественности описания классов.Но не радуйтесь.
Оказывается, эта естественность приводит к потере продуктивности.
Чтобы узнать, сколько стоит, сравним следующие характеристики:
- Создание объекта класса.
- Вызов метода.
- Доступ к собственности.
Пакет будет использоваться для тестирования.
В результатах испытаний обозначения следующие:
- vanilla — чистый Perl без дополнительных пакетов,
- лось - с пакетом Moose,
- moose_sig — с пакетом Moose и Method::Signatures,
- moosex — с пакетом MooseX.
package Dog;
sub new {
my ($class, %self) = @_;
bless \%self, $class;
return \%self;
}
sub make_noise {
my $self = shift;
say $self->{name}, " says: ruff-ruff!";
}
1;
Как видите, создание объектов с использованием всех пакетов ООП происходит почти в 4 раза медленнее, чем с использованием чистого Perl. Но есть одна хорошая новость: операция создания объекта с помощью Moose и MooseX::Declare занимает одинаковое время.
Поэтому, если вы используете один из этих пакетов, то предпочтение следует отдать MooseX::Declare. Вызов метода Перейдем к следующему пункту — вызову метода.
Здесь картина не столь примечательна: use Dog;
my $dog = Dog->new(name => "Snoopy");
$dog->make_noise();
MooseX проигрывает Moose (с подписями или без них) в 16 раз! Это, конечно, большой сюрприз.
Если вы покопаетесь в Интернете, то обнаружите, что причина такой большой разницы в производительности — пакет MooseX::Method::Signatures. Поэтому до тех пор, пока ситуация не улучшится, MooseX в таком виде использовать нельзя.
Однако хорошая новость заключается в том, что Moose + Method::Signatures всего на 20% медленнее, чем чистый Perl. Поэтому вы можете смело использовать эти пакеты без существенной потери производительности.
Доступ к собственности
Перейдем к последнему пункту тестов, обращению к свойству объекта: package Dog;
use Moose;
has name => (is => 'ro', isa => 'Str');
sub make_noise {
my $self = shift;
say $self->name(), " says: ruff-ruff!";
}
__PACKAGE__->meta->make_immutable;
Опять же, потеря всех пакетов по сравнению с чистым Perl составляет всего 20%.
Как видите, здесь MooseX оказался не хуже других пакетов.
Если бы не MooseX::Method::Signatures.
Исправление MooseX
Я очень хочу использовать MooseX, но это очень больно.Попробуем настроить его так, чтобы он был хоть немного лучше при вызове методов.
Первое, что приходит на ум, — использовать Method::Signatures вместе с MooseX::Declare. Давайте перепишем код Собака следующим образом: package Dog;
use Moose;
use Method::Signatures;
has name => (is => 'ro', isa => 'Str');
method make_noise() {
say $self->name(), " says: ruff-ruff!";
}
__PACKAGE__->meta->make_immutable;
Этот подход работает, но приводит к неприятному предупреждению: use MooseX::Declare;
class Dog {
has name => (is => 'ro', isa => 'Str');
method make_noise() {
say $self->name(), " says: ruff-ruff!";
}
}
Это факт метод — это простая функция Perl, определенная как MooseX::Method::Signatures, так и Method::Signatures. Но они определены с разными прототипами, поэтому и возникает предупреждение.
К сожалению, я не нашел, как убрать это предупреждение.
Поэтому мне пришлось придумать другое решение.
Метод::Сигнатуры::Простой Что может быть проще! Метод::Сигнатуры::Простой — это упрощенная версия Method::Signatures, имеющая одно хорошее свойство.
Здесь вы можете задать собственное имя для функции метод , что позволяет избежать конфликта с MooseX::Method::Signatures.
Используя этот пакет Собака будет выглядеть так: use MooseX::Declare;
class Dog {
use Method::Signatures;
has name => (is => 'ro', isa => 'Str');
method make_noise() {
say $self->name(), " says: ruff-ruff!";
}
}
Разница в том, что вместо метод мы сейчас пишем защита (как в Python).
Посмотрим, улучшилась ли производительность нашего кода (moosex_sig): use MooseX::Declare;
class Dog {
use Method::Signatures::Simple name => 'def';
has name => (is => 'ro', isa => 'Str');
def make_noise() {
say $self->name(), " says: ruff-ruff!";
}
}
Наши ожидания оправдались.
MooseX::Declare + Method::Signature::Simple обеспечивает ту же производительность, что и Moose + Method::Signatures.
Заключение
Несмотря на все богатство выбора, альтернатива вырисовывается только одна.На сегодняшний день моя лучшая рекомендация по использованию ООП в Perl — это комбинация пакетов MooseX::Declare и Method::Signatures::Simple. Он позволяет естественным образом описывать классы и имеет не очень высокую, можно даже сказать, вполне приемлемую цену с точки зрения производительности.
Приложение: Исходный код тестов доступен на github: github.com/alexeiz/oopbench Теги: #perl #ООП #производительность #perl #производительность #perl
-
Пул На Unity 3D
19 Oct, 24 -
Вручение Ux-Оскара В Нью-Йорке
19 Oct, 24 -
Казахстан Получил Кириллический Домен «.Kaz»
19 Oct, 24 -
Остерегайтесь Html5
19 Oct, 24 -
Быстрый Рейтинг В Itunes
19 Oct, 24