Perl OOPパッケージのパフォーマンス

Perlで知っているように、オブジェクト指向プログラミングのサポートはあまり便利ではありません。 クラスを使用してプログラミングする場合は、手動で多くの作業を行う必要があります。 ただし、Perlには非常に豊富な拡張オプションがあるため、時間の経過とともに、さまざまな利便性の構文でクラス、メソッド、およびプロパティをサポートする多くのライブラリ(パッケージ)が登場しました。 しかし、結局のところ、これらのパッケージは、OOP設計の手動実装と比較してパフォーマンスが低下します。 つまり 一方で、それらは使いやすく、他方ではコードを遅くします。 私はいつも、コードがどれだけ遅くなっているか、どのパッケージを使用すべきか、どのパッケージを使用すべきでないかを知りたいと思っていました。 そこで、私は少し研究することにしました。





OOPパッケージの概要


始めるために、Perlで利用可能なOOPパッケージを簡単に見ていきます。



ただperl


パッケージなしで、Perlのクラスを次のように作成できます。

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;
      
      





そのようなクラスは次のように使用できます。

 use Dog; my $dog = Dog->new(name => "Snoopy"); $dog->make_noise();
      
      





ムース


Mooseパッケージの中核は、Perl6のアイデアです。 これを使用してクラスを作成すると、桁違いに簡単になります。 Mooseで書き直された前の例は、ずっと良く見えるでしょう:

 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;
      
      





ご覧のとおり、 新しいメソッドを明示的に作成する必要はなくなり、プロパティははるかに簡単かつ自然に記述されるようになりました。 しかし、すべてがスムーズではありません。 クラスの各メソッドで$ selfパラメータを手動でアンパックする必要があります。 一般に、メソッドはperlovskim手順のままでした。 それらを通常の方法のように見せてほしい。



メソッド::署名


そして、この素晴らしいパッケージが私たちの助けになります: Method :: Signatures 。 ドキュメントを読むことをお勧めします-多くの楽しい驚きがあります。



それにより、コードはさらに良くなります。

 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;
      
      





MooseX ::宣言


Perlの支持者の好奇心はそこに留まらず、さらに先へ進み、 MooseX :: Declareを書きました 。 本当に素晴らしいパッケージです。1つの欠点(これについては後ほど)ではありません。 これで、 Dogクラスの説明で完全なnを達成できます。

 use MooseX::Declare; class Dog { has name => (is => 'ro', isa => 'Str'); method make_noise() { say $self->name(), " says: ruff-ruff!"; } }
      
      





OOPパッケージのパフォーマンス


Perlを使用すると、クラスの記述でほぼ完全な自然さを実現できます。 しかし、喜ばないでください。 この自然さが生産性の損失につながることがわかります。 方法を見つけるために、次のような特性を比較します。



それでは始めましょう。 ベンチマークはテストに使用されます。 テスト結果の表記は次のとおりです。



オブジェクト作成


               moose_sig moose moosexバニラの評価
 moose_sig 104102 / s--0%-0%-74%
ムース104383 / s 0%--0%-74%
 moosex 104592 / s 0%0%--74%
バニラ401924 / s 286%285%284%-


ご覧のとおり、すべてのOOPパッケージを使用したオブジェクトの作成は、純粋なPerlを使用した場合よりもほぼ4倍遅くなります。 しかし、良いニュースが1つあります。MooseとMooseXを使用してオブジェクトを作成する操作::宣言は同時に行われます。 したがって、これらのパッケージのいずれかを使用する場合は、MooseX :: Declareを優先する必要があります。



メソッド呼び出し


メソッドを呼び出して、次の段落に進みましょう。 ここでの写真はそれほど素晴らしいものではありません。



               moosex moose moose_sigバニラの評価
 moosex 8596 / s--94%-94%-95%
ムース148055 / s 1622%--0%-17%
 moose_sig 148516 / s 1628%0%--17%
バニラ178254 / s 1974%20%20%-


MooseXはMoose(署名の有無にかかわらず)を16回再生します! これはもちろん大きな驚きです。 インターネットを調べてみると、このようなパフォーマンスの大きな違いの理由は、MooseX :: Method :: Signaturesパッケージにあることがわかります。 したがって、状況が改善されるまで、MooseXはそのままでは使用できません。



ただし、良いニュースは、Moose + Method :: Signaturesが純粋なPerlよりもわずか20%遅いことです。 したがって、パフォーマンスを大幅に低下させることなく、これらのパッケージを安全に使用できます。



プロパティへのアクセス


テストの最後のポイントである、オブジェクトのプロパティへのアクセスに移りましょう。



                moosex moose_sigムースバニラの評価
 moosex 1503608 / s--1%-1%-17%
 moose_sig 1517928 / s 1%--0%-16%
ムース1517928 / s 1%0%--16%
バニラ1815063 / s 21%20%20%-


繰り返しますが、純粋なPerlと比較して、すべてのパッケージの損失はわずか20%です。 ご覧のとおり、ここでMooseXは他のパッケージより悪くありませんでした。 MooseX向けでない場合::メソッド::署名...



MooseXを修正


私は本当にMooseXを使いたいのですが、とても厄介です。 メソッドを呼び出すときに少なくとも少し良くなるように修正してみましょう。



最初に思い浮かぶのは、MooseX :: DeclareとともにMethod :: Signaturesを使用することです。 Dogコードを次のように書き換えます。

 use MooseX::Declare; class Dog { use Method::Signatures; has name => (is => 'ro', isa => 'Str'); method make_noise() { say $self->name(), " says: ruff-ruff!"; } }
      
      





このアプローチは機能しますが、い警告につながります:



サブルーチンDog :: /opt/local/lib/perl5/site_perl/5.14.1/darwin-thread-multi-2level/Devel/Declare/MethodInstaller/Simple.pm行17で再定義されたメソッド
プロトタイプの不一致:sub Dog ::メソッド:none /(&)/opt/local/lib/perl5/site_perl/5.14.1/darwin-thread-multi-2level/Devel/Declare/MethodInstaller/Simple.pm行17




実際のところ、 メソッドはMooseX :: Method :: SignaturesとMethod :: Signaturesの両方で定義される単純なPerl関数です。 しかし、それらは、警告がどこから来るかから、異なるプロトタイプで決定されます。 残念ながら、この警告を削除する方法は見つかりませんでした。 したがって、私は別の解決策を考え出さなければなりませんでした。



メソッド::署名::シンプル


何がもっと簡単になります! Method :: Signatures :: Simpleは、1つの優れた機能を備えたMethod :: Signaturesの簡易バージョンです。 その中で、 メソッド関数の名前を設定して、MooseX :: Method :: Signaturesとの競合を回避できます。



このパッケージを使用すると、 Dogは次のようになります。

 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!"; } }
      
      





違いは、 メソッドの代わりにdefを記述することです(Pythonのように)。



コード(moosex_sig)のパフォーマンスが改善されたかどうかを見てみましょう。



                moosex moosex_sig moose_sig mooseバニラの評価
 moosex 8651 / s--94%-94%-94%-95%
 moosex_sig 146152 / s 1589%--1%-3%-18%
 moose_sig 148025 / s 1611%1%--2%-17%
ムース150866 / s 1644%3%2%--16%
バニラ179200 / s 1971%23%21%19%-


期待に応えました。 MooseX :: Declare + Method :: Signature :: Simpleは、Moose + Method :: Signaturesと同じパフォーマンスを提供します。



おわりに


豊富な選択肢があるにもかかわらず、選択肢は1つだけです。 これまでのところ、PerlでOOPを使用するための私の観点からの最良の推奨事項は、MooseX :: DeclareおよびMethod :: Signatures :: Simple packagesの組み合わせです。 これにより、クラスを自然な方法で記述することができ、パフォーマンスに関してはあまり受け入れられないほどの価格があります。



補遺:テストのソースコードはgithubで入手できます: github.com/alexeiz/oopbench



All Articles